学习笔记|模数转换器|ADC原理|STC32G单片机视频开发教程(冲哥)|第十七集:ADC采集

news2024/9/28 1:22:13

文章目录

  • 1.模数转换器(ADC)是什么?
    • 手册说明:
  • 2.STC32G单片机ADC使用原理
    • 19.1.1 ADC控制寄存器(ADC_CONTR)
    • 19.1.2 ADC配置寄存器(ADCCFG)
    • 19.1.4ADC时序控制寄存器(ADCTIM)
    • 19.3 ADC相关计算公式
  • 3.编写最简单的ADC采集代码(查询&中断)
    • P10的引脚去获取一个ADC代码
    • 中断方式ADC的实现
  • 3.编写最简单的ADC采集代码
  • 总结
  • 课后练习:

1.模数转换器(ADC)是什么?

参考资料:adc模数转换器的作用。
模数转换器即A/D转换器,或简称ADC(Analog-to-digital converter),通常是指一个将模拟信号转变为数字信号的电子元件。
模拟信号 -> 电压
数字信号 -> 0和1组成的二进制数
那我们思考下我们单片机是怎么把模拟信号转化为数字信号的呢?
原理演示视频:见B站《逐次逼近型ADC转换过程的动画演示》。
简单的总结一下ADC到底是一个什么样的原理?
如果没有超,就写1,如果超了就写0.
分别测量一下两组板子的高度,从大到小一级一级的给它比较上去
结束以后是221.
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

如果增加比较的位数,精度更高:
在这里插入图片描述
在这里插入图片描述

当然这个位数也不是能一直无限制的高下去,毕竟环境噪声也会对他有所千扰(精度太高吹回气就有误差了)。
一般的话12位到16位绰绰有余。这就是ADC的一个转化的一个过程,一位一位的逐次转化。

手册说明:

ADC模数转换、传统DAC实现
STC32G系列单片机内部集成了一个12位高速AD转换器。ADC的时钟频率为系统频率。分频再经过用户设置的分频系数进行再次分频(ADC的时钟频率范围为SYSclk/2/1~SYSclk/2/16)。
ADC转换结果的数据格式有两种:左对齐和右对齐。可方便用户程序进行读取和引用。
注意:ADC 的第15通道是专门测量内部 1.19V参考信号源的通道,参考信号源值出厂时校准为1.19V,由于制造误差以及测量误差,导致实际的内部参考信号源相比1.19V,大约有土1%的误差。如果用户需要知道每一颗芯片的准确内部参考信号源值,可外接精准参考信号源,然后利用ADC的第15通道进行测量标定。ADC_VRef+脚外接参考电源时,可利用ADC的第15通道可以反推ADC_VRef+脚外接参考电源的电压;如将ADC_VREF+短接到MCU-VCC,就可以反推 MCU-VCC的电压。
如果芯片有ADC 的外部参考电源管脚ADC_VRef+,则一定不能浮空,必须接外部参考电源或者直接连到VCC。
假设单片机的基准电压为2.96V,以5V为例,比较结果如下:
在这里插入图片描述
注意:使用ADC功能时有Vref引脚的单片机千万千万千万不能悬空,必须接外部参考电压源或者VCC!!!

2.STC32G单片机ADC使用原理

19.1.1 ADC控制寄存器(ADC_CONTR)

在这里插入图片描述
在这里插入图片描述
只有15个引脚,可以使用单片机的ADC,不是所有引脚都能使用ADC功能,只有指定的这个ADC的通道(1.19V参考),这15个才能进行ADC的一个转化。
ADC_EPWMT:使能PWM实时触发ADC功能。详情请参考16位高级PWM定时器章节,本节暂时略过,不详细探讨。
如ADC_CHS3:0写0000,就可以使用P1.0。

19.1.2 ADC配置寄存器(ADCCFG)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
时钟建议选一个慢一点的时钟,设置的时间可以看{FADC=SYSclk/2/(SPEED+1)},不继续深入。实际上ADC大部分使用的情况都和时间没有太大影响。
时钟选择手册中的默认值就可以。

19.1.4ADC时序控制寄存器(ADCTIM)

在这里插入图片描述
一般建议均使用默认值。(注意:SMPDUTY一定不能设置小于01010B),即从参数图上看,建议往下不要再往上走。
12位ADC的转换时间固定为12个ADC工作时钟。
一个完整的ADC转换时间为:Tsetup+Tduty+ Thold+Tconvert、如下图所示:
在这里插入图片描述

19.3 ADC相关计算公式

19.3.1 ADC速度计算公式本次不涉及。
在这里插入图片描述
在这里插入图片描述

19.4.1 一般精度ADC参考线路图
在这里插入图片描述
19.4.2高精度ADC参考线路图
在这里插入图片描述
两者的主要区别在于VREF的处理,高精度的ADC有独立的基准2.5V电压源。
不建议使用串口电路,易受供电电压波动影响。
建议使用:ISP下载典型应用线路图中的USB接线电路,比串口更方便,更实用。
在这里插入图片描述
在这里插入图片描述

3.编写最简单的ADC采集代码(查询&中断)

官方查询方式例程为:
在这里插入图片描述
在这里插入图片描述

P1M0= 0x00;P1M1 = 0x01; //将IO口P1.0设置为高阻状态。
可以在STC-ISP中找到相应设置,选择接口和拟设置的端口模式,自动生成代码,可以直接复制。
在这里插入图片描述

三个主要的寄存器配置:

ADCTIM= 0x3f;   //设置ADC内部时序  0x3f=0011 1111
ADCCFG= 0x0f;    //设置ADC时钟为系统时钟/2/16/16
ADC_POWER = 1;    //使能ADC模块

编写代码之前,需要看一下原理图(实验箱9.6_2022-12-05-SCH)上,我们的芯片ADC使用哪个引脚:
在这里插入图片描述

P10的引脚去获取一个ADC代码

以上节的12.IO中断为模板,复制并修改为13.ADC模拟电压采集.
\HARDWARE文件夹下新建ADC子目录,并新建adc.c和adc.h,把ADCH添加进我们的路径里。添加.h文件模板,在.c和主文件内引用。
我们把它我们的ADC也先初始化一下,添加函数声明及定义。
adc.h为:

#ifndef __ADC_H
#define __ADC_H

#include "COMM/stc.h"			//调用头文件
#include "COMM/usb.h"

//------------------------引脚定义------------------------//


//------------------------变量声明------------------------//


//------------------------函数声明-----------------------//
void ADC_Init(void); 	//ADC初始化
u16 ADC_Read(u8 no );	//ADC读取指定通道的adc电压
#endif

adc.c为:

#include "adc.h"
#include "intrins.h"

//========================================================================
// 函数名称:ADC_Init
// 函数功能:ADC初始化
// 入口参数:无
// 函数返回:无
// 当前版本: VER1.0
// 修改日期: 2023
// 当前作者:
// 其他备注:
//========================================================================
void ADC_Init(void)		//ADC初始化
{
	P1M0 = 0x00;	//设置P1.0引脚为高阻输入,参考点亮LED章节
	P1M1 = 0x01;

	ADCTIM= 0x3f;   //设置ADC内部时序  0x3f=0011 1111
	ADCCFG= 0x2f;   //设置ADC为数据右对齐。时钟为系统时钟/2/16/16  0x2f=0010 1111
	ADC_POWER = 1;  //使能ADC模块
}

//========================================================================
// 函数名称:ADC_Read
// 函数功能:读取指定通道的adc电压
// 入口参数: @no:通道0-15
// 函数返回:当前的12位adc数值
// 当前版本: VER1.0
// 修改日期: 2023
// 当前作者:
// 其他备注:
//========================================================================

u16 ADC_Read(u8 no)						//读取指定通道的adc电压
{
	u16 adcval;							//adc数值保存变量
	ADC_CONTR &= 0xf0;					//清空通道,要保持它的低4位为0
	ADC_CONTR |= no;					//选择通道
	ADC_START = 1;						//开启ADC通道
	_nop_();
	_nop_();							//空操作指令,比delay远远短
	while(!ADC_FLAG);					//等待转换结束。ADC_FLAG:ADC转换结束标志位。当ADC完成一次转换后,硬件会自动将此位置1,并向CPU提出中断请求。
	ADC_FLAG = 0;						//此标志位必须软件清零。
	adcval = (ADC_RES << 8) + ADC_RESL;	//计算adc的数值,我们这边给它右对齐一下(最高4位恒定是0)
	return adcval;
}

在主函数里面,去循环的读取那个adc的数值。新建u16变量,保存adc的数值:u16 ADC_VAL; //ADC的数值
demo.c:

#include "COMM/stc.h"		//调用头文件
#include "COMM/usb.h"
#include "seg_led.h"
#include "key.h"			//调用头文件
#include "beep.h"
#include "tim0.h"
#include "exit.h"
#include "adc.h"


#define MAIN_Fosc 24000000UL	//定义主时钟

char *USER_DEVICEDESC = NULL;
char *USER_PRODUCTDESC = NULL;
char *USER_STCISPCMD = "@STCISP#";

bit TIM_10MS_Flag;		//10ms标志位

void sys_init();	//函数声明
void delay_ms(u16 ms);

void Timer0_Isr(void);

u16 Time_CountDown = 0;	//全局变量,文件里所有地方都可以调用 大于255定义u16

void main()					//程序开始运行的入口
{
	u16 ADC_VAL;			//ADC的数值
	sys_init();				//USB功能+IO口初始化
	usb_init();				//usb库初始化
	Timer0_Init();			//定时器0初始化

	ADC_Init();

	EA = 1;					//CPU开放中断,打开总中断。

	while(1)		//死循环
	{
		delay_ms(2);								//让USB稳定下来
//		if( DeviceState != DEVSTATE_CONFIGURED ) 	//
//			continue;
		if( bUsbOutReady )
		{
			usb_OUT_done();
		}
		if(TIM_10MS_Flag == 1)   					//将需要延时的代码部分放入
		{
			TIM_10MS_Flag = 0;						//TIM_10MS_Flag 变量清空置位
		}
		ADC_VAL = ADC_Read(0);						//保存ADC的数值,使用P10,即取0
		printf("当前ADC数\XFD值:%d\r\n",(int)ADC_VAL); //打印ADC的数值,直接打印会出乱码,数后面需要加\XFD
	}
}

void sys_init()		//函数定义
{
    WTST = 0;  //设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
    EAXFR = 1; //扩展寄存器(XFR)访问使能
    CKCON = 0; //提高访问XRAM速度

	P0M1 = 0x00;   P0M0 = 0x00;   //设置为准双向口
    P1M1 = 0x00;   P1M0 = 0x00;   //设置为准双向口
    P2M1 = 0x00;   P2M0 = 0x00;   //设置为准双向口
    P3M1 = 0x00;   P3M0 = 0x00;   //设置为准双向口
    P4M1 = 0x00;   P4M0 = 0x00;   //设置为准双向口
    P5M1 = 0x00;   P5M0 = 0x00;   //设置为准双向口
    P6M1 = 0x00;   P6M0 = 0x00;   //设置为准双向口
    P7M1 = 0x00;   P7M0 = 0x00;   //设置为准双向口

    P3M0 = 0x00;
    P3M1 = 0x00;

    P3M0 &= ~0x03;
    P3M1 |= 0x03;

    //设置USB使用的时钟源
    IRC48MCR = 0x80;    //使能内部48M高速IRC
    while (!(IRC48MCR & 0x01));  //等待时钟稳定

    USBCLK = 0x00;	//使用CDC功能需要使用这两行,HID功能禁用这两行。
    USBCON = 0x90;
}


void delay_ms(u16 ms)	//unsigned int
{
	u16 i;
	do
	{
		i = MAIN_Fosc/6000;
		while(--i);
	}while(--ms);
}

void Timer0_Isr(void) interrupt 1 		//1ms进来执行一次,无需其他延时,重复赋值
{
	static timecount = 0;

	SEG_LED_Show();		//数码管刷新

	timecount++;		//1ms+1
	if(timecount>=10)	//如果这个变量大于等于10,说明10ms到达
	{
		timecount = 0;
		TIM_10MS_Flag = 1;	//10ms到了
	}
}

编译下载,串口持续打印0,1。
根据原理图,可以按下按键改变adc的值。按下按键,得到的打印结果与原理图一致。
这里使用的源为高精度基准电压2.5V,默认焊接R79,如图:
在这里插入图片描述

也可以用万用表的电压档,测量ADC的实际基准电压,红正,黑接地。

表上显示2.498伏非常的稳定,这个就是基准电压源。

再测一下ADC的数值,测量R27的电阻边上,测量得到读数与原理图可以对照。
也可以用计算器来换算一下,看看电压是否正确:
在这里插入图片描述

可以根据这个反推出一个(引脚上的)电源电压。
增加函数:u16 ADC_CAL_Voltage(u16 num)

u16 ADC_CAL_Voltage(u16 num)
{
	return num*2.5*1000/4096;
}

将读取和打印代码移入延时代码段内,实现10ms检测打印1次:

		if(TIM_10MS_Flag == 1)   					//将需要延时的代码部分放入
		{
			TIM_10MS_Flag = 0;						//TIM_10MS_Flag 变量清空置位
			ADC_VAL = ADC_Read(0);						//保存ADC的数值,使用P10,即取0
			printf("当前ADC数\xfd值:%d\t%d\r\n",(int)ADC_VAL,ADC_CAL_Voltage(ADC_VAL)); //打印ADC的数值,直接打印会出乱码,数后面需要加\XFD}
		}

编译,下载。不点击按钮时,显示0,按下按钮,显示256,156mv。

中断方式ADC的实现

只是多了一个EADC的这个操作:EADC=1;
我们如果需要在中断里面一直循环,那我们就一直开启。增加void ADC_Init(void)和void ADC_Isr() interrupt 5:

void ADC_Init(void)		//ADC初始化
{
	P1M0 = 0x00;	    //设置P1.0引脚为高阻输入,参考点亮LED章节
	P1M1 = 0x01;

	ADCTIM= 0x3f;       //设置ADC内部时序  0x3f=0011 1111
	ADCCFG= 0x2f;       //设置ADC为数据右对齐。时钟为系统时钟/2/16/16  0x2f=0010 1111
	ADC_POWER = 1;      //使能ADC模块
	EADC = 1;		    //开启中断模式
}

void ADC_Isr() interrupt 5
{
	ADC_FLAG = 0;							//此标志位必须软件清零,清空读取标志位
	adc_val =  = (ADC_RES << 8) + ADC_RESL;	//读取adc的数值,我们这边给它右对齐一下(最高4位恒定是0)
	ADC_START = 1;							//开启ADC通道

}

3.编写最简单的ADC采集代码

这里有一个问题,ADC_Init查询模式和中断模式都进行了定义且同名,编译会出现错误。需要采用条件编译来规避。

HARDWARE\ADC\adc.c(75): error C53: redefinition of 'ADC_Init': function already defined

引入if预编译模板:

#define ADC_CHECK  0 	    //查询
#define ADC_Isr          1 	//中断

#define  ADC_Func  ADC_CHECK

#if ADC_Func == ADC_CHECK
//adc查询的相关定义
#elif ADC_Func == ADC_Isr
//adc中断的相关定义
#else

#endif

将模板插入adc.h,并修改:

#ifndef __ADC_H
#define __ADC_H

#include "COMM/stc.h"			//调用头文件
#include "COMM/usb.h"

#define ADC_CHECK  0 	   	 	//查询
#define ADC_Isr    1 			//中断

#define  ADC_Func  ADC_CHECK	//最终选择

#if ADC_Func == ADC_CHECK
	//adc查询的相关定义
#elif ADC_Func == ADC_Isr
	//adc中断的相关定义
#else

#endif

//------------------------引脚定义------------------------//


//------------------------变量声明------------------------//

extern u16 adc_val;			//中断获取到的ADC数值
//------------------------函数声明-----------------------//
void ADC_Init(void); 	//ADC初始化
u16 ADC_Read(u8 no );	//ADC读取指定通道的adc电压
u16 ADC_CAL_Voltage(u16 num);

#endif

adc的这个数值非常重要,比如说报警的时候,假设我们检测外部有没有着火。
当这个adc的数值非常大(假设火越大,传感器出来的电压也越大),表示外面已经着火的时候,这个时候就要立马执行灭火,要不然的话,火势一起来就已经灭不掉火了

编译,下载。运行时,按下按钮没有反应。
排查:先跳转到初始化,发现ADC_Init跳转到了查询代码段,实际上要用的是中断的初始化,然后我们才可以进入。
需要把头文件中的查询换成中断:#define ADC_Func ADC_Isr //编译选择
修改后的代码如下:
adc.c:

#include "adc.h"
#include "intrins.h"

u16 adc_val;				//获取到的ADC数值

#if ADC_Func == ADC_CHECK
	//adc查询的相关定义
	//========================================================================
	// 函数名称:ADC_Init
	// 函数功能:ADC初始化
	// 入口参数:无
	// 函数返回:无
	// 当前版本: VER1.0
	// 修改日期: 2023
	// 当前作者:
	// 其他备注:
	//========================================================================
	void ADC_Init(void)		//ADC初始化
	{
		P1M0 = 0x00;	//设置P1.0引脚为高阻输入,参考点亮LED章节
		P1M1 = 0x01;

		ADCTIM= 0x3f;   //设置ADC内部时序  0x3f=0011 1111
		ADCCFG= 0x2f;   //设置ADC为数据右对齐。时钟为系统时钟/2/16/16  0x2f=0010 1111
		ADC_POWER = 1;  //使能ADC模块
	}

	//========================================================================
	// 函数名称:ADC_Read
	// 函数功能:读取指定通道的adc电压
	// 入口参数: @no:通道0-15
	// 函数返回:当前的12位adc数值
	// 当前版本: VER1.0
	// 修改日期: 2023
	// 当前作者:
	// 其他备注:
	//========================================================================


	u16 ADC_Read(u8 no)						//读取指定通道的adc电压
	{
		u16 adcval;							//adc数值保存变量
		ADC_CONTR &= 0xf0;					//清空通道,要保持它的低4位为0
		ADC_CONTR |= no;					//选择通道
		ADC_START = 1;						//开启ADC通道
		_nop_();
		_nop_();							//空操作指令,比delay远远短
		while(!ADC_FLAG);					//等待转换结束。ADC_FLAG:ADC转换结束标志位。当ADC完成一次转换后,硬件会自动将此位置1,并向CPU提出中断请求。
		ADC_FLAG = 0;						//此标志位必须软件清零。
		adcval = (ADC_RES << 8) + ADC_RESL;	//计算adc的数值,我们这边给它右对齐一下(最高4位恒定是0)
		return adcval;
	}

#elif ADC_Func == ADC_Isr
		//adc中断的相关定义
	//========================================================================
	// 函数名称:ADC_Init
	// 函数功能:中断的ADC初始化
	// 入口参数:无
	// 函数返回:无
	// 当前版本: VER1.0
	// 修改日期: 2023
	// 当前作者:
	// 其他备注:
	//========================================================================

	void ADC_Init(void)		//ADC初始化
	{
		P1M0 = 0x00;		//设置P1.0引脚为高阻输入,参考点亮LED章节
		P1M1 = 0x01;

		ADCTIM= 0x3f;   	//设置ADC内部时序  0x3f=0011 1111
		ADCCFG= 0x2f;   	//设置ADC为数据右对齐。时钟为系统时钟/2/16/16  0x2f=0010 1111
		ADC_POWER = 1;  	//使能ADC模块
		EADC = 1;			//打开中断
		ADC_START = 1;		//开启ADC通道
	}
	//========================================================================
	// 函数名称:ADC_iSR
	// 函数功能:
	// 入口参数: @
	// 函数返回:
	// 当前版本: VER1.0
	// 修改日期: 2023
	// 当前作者:
	// 其他备注:
	//========================================================================

	void ADC_iSR()interrupt 5					//这里不能使用ADC_Isr(),会与预定义“#define ADC_Isr    1  //中断 ”混淆
	{
		ADC_FLAG = 0;							//此标志位必须软件清零,清空读取标志位
		adc_val = (ADC_RES << 8) + ADC_RESL;	//读取adc的数值,我们这边给它右对齐一下(最高4位恒定是0)
		ADC_START = 1;							//开启ADC通道
	}

#else

#endif

//========================================================================
// 函数名称:ADC_CAL_Voltage
// 函数功能:将ADC数值换算成电源电压
// 入口参数: @num:ADC的数值,取值范围0-4095
// 函数返回:电源电压 单位mv
// 当前版本: VER1.0
// 修改日期: 2023
// 当前作者:
// 其他备注:
//========================================================================
u16 ADC_CAL_Voltage(u16 num)
{
	return num*2.5*1000/4096;
}

adc.h:

#ifndef __ADC_H
#define __ADC_H

#include "COMM/stc.h"			//调用头文件
#include "COMM/usb.h"

#define ADC_CHECK  0 	   	 	//查询
#define ADC_Isr    1 			//中断

#define  ADC_Func  ADC_Isr		//编译选择


//------------------------引脚定义------------------------//


//------------------------变量声明------------------------//

extern u16 adc_val;				//中断获取到的ADC数值
//------------------------函数声明-----------------------//
void ADC_Init(void);	//ADC初始化
u16 ADC_Read(u8 no);	//ADC读取指定通道的adc电压
u16 ADC_CAL_Voltage(u16 num);

#endif

demo.c:

#include "COMM/stc.h"		//调用头文件
#include "COMM/usb.h"
#include "seg_led.h"
#include "key.h"			//调用头文件
#include "beep.h"
#include "tim0.h"
#include "exit.h"
#include "adc.h"


#define MAIN_Fosc 24000000UL	//定义主时钟

char *USER_DEVICEDESC = NULL;
char *USER_PRODUCTDESC = NULL;
char *USER_STCISPCMD = "@STCISP#";

bit TIM_10MS_Flag;		//10ms标志位

void sys_init();	//函数声明
void delay_ms(u16 ms);

void Timer0_Isr(void);

u16 Time_CountDown = 0;	//全局变量,文件里所有地方都可以调用 大于255定义u16

void main()					//程序开始运行的入口
{
	//u16 ADC_VAL;			//ADC的数值
	sys_init();				//USB功能+IO口初始化
	usb_init();				//usb库初始化
	Timer0_Init();			//定时器0初始化

	ADC_Init();

	EA = 1;					//CPU开放中断,打开总中断。

	while(1)		//死循环
	{
		delay_ms(2);								//让USB稳定下来
//		if( DeviceState != DEVSTATE_CONFIGURED ) 	//
//			continue;
		if( bUsbOutReady )
		{
			usb_OUT_done();
		}
		if(TIM_10MS_Flag == 1)   					//将需要延时的代码部分放入
		{
			TIM_10MS_Flag = 0;						//TIM_10MS_Flag 变量清空置位

			//ADC_VAL = ADC_Read(0);						//保存ADC的数值,使用P10,即取0

			printf("当前ADC数\xfd值:%d\t%dmv\r\n",(int)adc_val,ADC_CAL_Voltage(adc_val)); //打印ADC的数值,直接打印会出乱码,数后面需要加\XFD,单位mv
		}
	}
}

void sys_init()		//函数定义
{
    WTST = 0;  //设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
    EAXFR = 1; //扩展寄存器(XFR)访问使能
    CKCON = 0; //提高访问XRAM速度

	P0M1 = 0x00;   P0M0 = 0x00;   //设置为准双向口
    P1M1 = 0x00;   P1M0 = 0x00;   //设置为准双向口
    P2M1 = 0x00;   P2M0 = 0x00;   //设置为准双向口
    P3M1 = 0x00;   P3M0 = 0x00;   //设置为准双向口
    P4M1 = 0x00;   P4M0 = 0x00;   //设置为准双向口
    P5M1 = 0x00;   P5M0 = 0x00;   //设置为准双向口
    P6M1 = 0x00;   P6M0 = 0x00;   //设置为准双向口
    P7M1 = 0x00;   P7M0 = 0x00;   //设置为准双向口

    P3M0 = 0x00;
    P3M1 = 0x00;

    P3M0 &= ~0x03;
    P3M1 |= 0x03;

    //设置USB使用的时钟源
    IRC48MCR = 0x80;    //使能内部48M高速IRC
    while (!(IRC48MCR & 0x01));  //等待时钟稳定

    USBCLK = 0x00;	//使用CDC功能需要使用这两行,HID功能禁用这两行。
    USBCON = 0x90;
}


void delay_ms(u16 ms)	//unsigned int
{
	u16 i;
	do
	{
		i = MAIN_Fosc/6000;
		while(--i);
	}while(--ms);
}

void Timer0_Isr(void) interrupt 1 		//1ms进来执行一次,无需其他延时,重复赋值
{
	static timecount = 0;

	SEG_LED_Show();		//数码管刷新

	timecount++;		//1ms+1
	if(timecount>=10)	//如果这个变量大于等于10,说明10ms到达
	{
		timecount = 0;
		TIM_10MS_Flag = 1;	//10ms到了
	}
}

总结

1.了解ADC的位数、引脚、基准电压、等关键名词。
2.学会ADC的原理,学会用法和电源的换算公式。

课后练习:

简易电压表:
1.用前4位数码管显示ADC的数值
2.用后四位数码管显示最终电压。
3.电压大于2.2V,蜂鸣长响,表示快要到达上限

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1026194.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

网络安全第一次作业

1、什么是防火墙 防火墙是一种网络安全系统&#xff0c;它根据预先确定的安全规则监视和控制传入和传出的网络流量。其主要目的是阻止对计算机或网络的未经授权的访问&#xff0c;同时允许合法通信通过。 防火墙可以在硬件、软件或两者的组合中实现&#xff0c;并且可以配置为根…

嵌入式:驱动开发 Day9

作业&#xff1a;通过platform总线驱动实现 a.应用程序通过阻塞的io模型来读取number变量的值 b.number是内核驱动中的一个变量 c.number的值随着按键按下而改变&#xff08;按键中断&#xff09; 例如number0 按下按键number1 ,再次按下按键number0 d.在按下按键的时候需要同时…

VHOST-SCSI代码分析(1)VHOST SCSI设备模拟

VHOST SCSI设备的模拟是由QEMU和HOST共同实现的&#xff0c;QEMU模拟VHOST SCSI设备配置空间等&#xff0c;而对于虚拟机通知HOST和HOST通知虚拟机机制由HOST内核实现。 在QEMU中VHOST SCSI设备继承关系如下&#xff1a; 其它设备以及对应class_init函数和realize具现化实现与V…

什么是亲子经济,小红书母婴品牌营销须知!

亲子经济已经成为当今社会的新兴概念&#xff0c;今天将要探讨亲子经济的定义、重要性以及&#xff0c;什么是亲子经济&#xff0c;小红书母婴品牌营销须知&#xff01; 一、亲子经济的定义与重要性 1.定义 亲子经济是指以儿童和家庭为中心的经济活动。其中包括了亲子旅游、教育…

中国股市杠杆是多少倍?炒股加9倍杠杆可行不?

中国股市杠杆通常情况下是在3&#xff5e;5倍之间&#xff0c;而在某些情况下&#xff0c;最高可能有十倍的杠杆。 杠杆炒股&#xff0c;即融资融券交易&#xff0c;是一种高风险高收益的投资方式。通过融资融券交易&#xff0c;投资者可以借入资金来扩大自己的投资规模&#…

容器管理工具 Docker生态架构及部署

目录 一、Docker生态架构 1.1 Docker Containers Are Everywhere 1.2 生态架构 1.2.1 Docker Host 1.2.2 Docker daemon 1.2.3 Registry 1.2.4 Docker client 1.2.5 Image 1.2.6 Container 1.2.7 Docker Dashboard 1.3 Docker版本 二、Docker部署 2.1 使用YUM源部署…

【Linux基础】第31讲 Linux用户和用户组权限控制命令(三)

用户组管理命令 每个用户都有一个用户组&#xff0c;系统可以对一个用户组中的所有用户进行集中管理。不同Linux系统对用户组的规定有所不同。如Linux下的用户属于与它同名的用户组&#xff0c;这个用户组在创建用户时同时创建。用户组的管理涉及用户组的添加、删除和修改。组…

Jmeter 分布式压测

‍你可以使用 JMeter 来模拟高并发秒杀场景下的压力测试。这里有一个例子&#xff0c;它模拟了同时有 5000 个用户&#xff0c;循环 10 次的情况‍。 请求默认配置 token 配置 秒杀接口 结果分析 但是&#xff0c;实际企业中&#xff0c;这种压测方式根本不满足实际需求。下面介…

IPv6协议基本概念

目前大多数设备节点支持IPv6和IPv4双栈,但随着IPv6逐渐应用,某些设备已经只支持纯IPv6,即IPv6 Only。 一、IPv6地址格式 1、IPv6地址表示方式 IPv6可以写成一组8个十六进制数,用冒号(:)分割。也可以写成128位2进制的0和1。 32即8x4,8表示8组16进制数,4表示每组16禁止包…

Vivado下PLL实验

文章目录 前言一、CMT&#xff08;时钟管理单元&#xff09;1、CMT 简介2、FPGA CMT 框图3、MMCM 框图4、PLL 框图 二、创建工程1、创建工程2、PLL IP 核配置3、进行例化 三、进行仿真1、创建仿真文件2、进行仿真设置3、进行行为级仿真 四、硬件验证1、引脚绑定2、生成比特流文…

QT-day4

画一个时钟 widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QPaintEvent> #include <QDebug> #include <QPainter> #include <QTimer> #include <QTime>QT_BEGIN_NAMESPACE namespace Ui { class Widget; } Q…

红队打靶:Fowsniff打靶思路详解(vulnhub)

目录 写在开头 第一步&#xff1a;主机发现和端口扫描 第二步&#xff1a;Web渗透 第三步&#xff1a;pop3服务器渗透 第四步&#xff1a;获取初始立足点 第五步&#xff1a;ssh登陆的banner脚本提权 总结与思考 写在开头 本篇博客在自己的理解之上根据大佬红队笔记的…

初学phar反序列化

以下内容参考大佬博客&#xff1a;PHP Phar反序列化浅学习 - 跳跳糖 首先了解phar是什么东东 Phar是PHP的压缩文档&#xff0c;是PHP中类似于JAR的一种打包文件。它可以把多个文件存放至同一个文件中&#xff0c;无需解压&#xff0c;PHP就可以进行访问并执行内部语句。 默认开…

性能测试 —— Tomcat监控与调优:Jconsole监控

JConsole的图形用户界面是一个符合Java管理扩展(JMX)规范的监测工具&#xff0c;JConsole使用Java虚拟机(Java VM)&#xff0c;提供在Java平台上运行的应用程序的性能和资源消耗的信息。在Java平台&#xff0c;标准版(Java SE平台)6&#xff0c;JConsole的已经更新到目前的外观…

Windows平台Qt6中UTF8与GBK文本编码互相转换、理解文本编码本质

快速答案 UTF8转GBK QString utf8_str"中UTF文"; std::string gbk_str(utf8_str.toLocal8Bit().data());GBK转UTF8 std::string gbk_str_given_by_somewhere"中GBK文"; QString utf8_strQString::fromLocal8Bit(gbk_str_given_by_somewhere.data());正文…

20-SpringCloudAlibaba-3

七 分布式事物处理 1 认识本地事物 什么是事物 事务就是针对数据库的一组操作&#xff0c;它可以由一条或多条SQL语句组成&#xff0c;同一个事务的操作具备同步的特点&#xff0c;事务中的语句要么都执行&#xff0c;要么都不执行。 举个栗子&#xff1a; 你去小卖铺买东西&…

《已解决 Bug TypeError: Cannot read property ‘props‘ of undefined (React)》

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页: &#x1f405;&#x1f43e;猫头虎的博客&#x1f390;《面试题大全专栏》 &#x1f995; 文章图文并茂&#x1f996…

2023_Spark_实验十一:RDD高级算子操作

//checkpoint &#xff1a;sc.setCheckpointDir("hdfs://Master:9000/ck") // 设置检查点val rdd sc.textFile("hdfs://Master:9000/input/word.txt").flatMap(_.split(" ")).map((_,1)).reduceByKey(__) // 执行wordcount任务的转换rdd.checkp…

Windows虚拟机访问网页证书错误问题

问题&#xff1a; 显示证书错误&#xff0c;图片加载不出来&#xff0c;看着很别扭&#xff0c;如下&#xff1a; 方法: 1.先导出可用的证书&#xff1a; 可以将自己正常环境的证书导出来&#xff08;google浏览器为例&#xff09; 浏览器右上角三个竖点——设置——隐私设…

阿里云服务器开放的一个新端口,重启防火墙,端口未启动

问题&#xff1a; 阿里云网页开放的一个新端口后&#xff0c;重启防火墙&#xff0c;端口未启动&#xff0c;之前配置的也都停止了。 解决&#xff1a; 原因可能是阿里的服务控制了&#xff0c;只能一个个端口开启了。把新配置新端口也单独启用。 开启80端口指令 firewall-cm…