yzk_hi
发表于 2024-4-29 08:50:20
打卡十三集
组织小白
发表于 2024-4-29 09:24:12
科学妞妞 发表于 2024-4-29 08:33
就是按时间的流水,操作逻辑运算,按步骤,有中断的时候,按中断,知道大概个意思,知道有寄存器这回事, ...
{:victory:}
组织小白
发表于 2024-4-29 09:24:46
科学妞妞 发表于 2024-4-29 08:34
加油
{:victory:}
Rain_Personal
发表于 2024-4-29 11:18:48
后面越来越难了
好学天上
发表于 2024-4-29 11:50:44
第十四集矩阵按键打卡,胜利就在不远处!{:victory:}
STC32G128K芯片学习打卡贴
https://www.stcaimcu.com/forum.php?mod=viewthread&tid=7834
(出处: 国芯技术交流网站)
bnnpyuvtkd
发表于 2024-4-29 13:46:42
本帖最后由 bnnpyuvtkd 于 2024-4-29 16:10 编辑
第17讲:模数转换器ADC上
1、数模转换器是什么?
2、STC32G单片机ADC使用原理
一、ADC相关的寄存器
(1)、ADC控制寄存器(ADC_CONTR) , PWM触发ADC控制
符号 地址 B7 B6 B5 B4 B3 B2 B1B0
ADC_CONTR BCH ADC_POWER ADC_START ADC_FLAG ADC_EPWMT ADC_CHS
ADC_POWER:ADC 电源控制位
0:关闭ADC电源
1:打开ADC电源
建议进入空闲模式和掉电模式前将ADC电源关闭,已将低功耗
特别注意:
1、给MCU的内部ADC模块电源打开后,需等待约1ms,等MCU内部的ADC电源稳定后再让ADC工作:
2、适当加长对外部信号的采样时间,就是对ADC内部采样保持电容的充电或放电时间,时间够,内部才能和外部电势相等。
ADC_START:ADC转换启动控制位。写入1后开始ADC转换,转换完成后硬件自动将此位清0 。
0:无影响。即使ADC已经开始转换工作,写0也不会停止A/D转换。
1:开始ADC转换,转换完成后硬件自动将此位清0 。
ADC_FLAG:ADC转换结束标志位。当ADC完成一次转换后,硬件会自动将此位置1 ,并向CPU提出中断要求。此标志位必须软件清0 。
ADC_EPWMT:使能PWM实时触发ADC功能。详情请参考16位高级PWM定时器章节。
ADC_CHS:ADC模拟通道选择位。
(注意:被选择为ADC输入通道的I/O口,必须设置PxM0/PxM1寄存器将I/O口设置为高阻输入模式。另外如果MCU进入主时钟停振/省电模式后,仍需要使能ADC通道,则需要设置PxIE寄存器关闭数字输入通道,以防止外部模拟输入信号忽高忽低而产生额外的功耗)
ADC_CHS ADC通道 ADC_CHS ADC通道
0000 P1.0 1000 P0.0
0001 P1.1 1001 P0.1
0010 P1.2/P5.4 1010 P0.2
0011 P1.3 1011 P0.3
0100 P1.4 1100 P0.4
0101 P1.5 1101 P0.5
0110 P1.6 1110 P0.6
0111 P1.7 1111 测试内部1.19V
有P1.2口的型号,此功能在P1.2口上,对于无P1.2口的型号,此功能在P5.4扣上。特别是:STC32G8K64系列的ADC通道2在P5.4
(2)、ADC配置寄存器(ADCCFG)
符号 地址 B7 B6 B5 B4 B3 B2 B1 B0
ADCCFG DEH - - RESFMT - SPEED
RESFMT:ADC转换结果格式控制位
0:转换结果左对齐。ADC_RES保存结果的高8位,ADC_RESL保存结果的低4位。格式如下:
ADC_RES ADC_RESL
D11,D10,D9,D8,D7,D6,D5,D4 D3,D2,D1,D0, 0,0,0,0
1_______________________________________________________11_________1
12位换算结果 自动添0
RESFMT = 0
1:换算结果右对齐。ADC_RES保存结果的高4位,ADC_RESL保存结果的低8位。格式如下:
ADC_RES ADC_RESL
0 ,0 ,0 ,0 ,D11,D10,D9,D8 D7,D6,D5,D4,D3,D2,D1,D0
1__________1 1_______________________________________________________1
自动添0 12位换算结果
RESFMT = 1
SPEED:设置ADC时钟{FADC=SYSclk/2/(SPEED+1)}
SPEED ADC时钟频率
0000 SYSclk/2/1
0001 SYSclk/2/2
0010 SYSclk/2/3
______ ______
1101 SYSclk/2/14
1110 SYSclk/2/15
1111 SYSclk/2/16
(3)、ADC转换结果寄存器(ADC_RES,ADC_RESL)
符号 地址 B7 B6 B5 B4 B3 B2 B1 B0
ADC_RES BDH
ADC_RESL BDH
当A/D转换完成后,转换结果会自动保存到ADC_RES和ADC_RESL中。保存结果的数据格式请参考ADC_CFG寄存器中的RESFMT设置。
(4)、ADC时序控制寄存器(ADCTIM)
符号 地址 B7 B6 B5 B4B3B2B1B0
ADCTIM 7EFEA8H CSSETUP CSHOLD SMPDUTY
CSSETUP:ADC通道选择时间控制Tsetup
CSSETUP ADC时钟
0 1(默认值)
1 2
CSHOLD:ADC通道选择保持时间控制Thold
CSHOLD ADC时钟数
00 1
01 2(默认值)
10 3
11 4
SMPDUTY:ADC模拟信号采样时间控制Tcuty(注意:SMPDUTY一定不能设置小于01010B)
SMPDUTY ADC时钟数
00000 1
00001 2
.... ....
01010 11(默认值)
.... ....
11110 31
11111 32
二、ADC整体转换时序图
ADC模拟转换时间:Tconvert
12位ADC的转换时间固定为12个ADC工作时钟
一个完整的ADC转换时间为:Tsetup + Tduty + Thold + Tconvert,如下图所示
3、ADC静态特征
符号描述最小值典型值最大值单位
RES分辨率 12 Bits
ET整体误差 0.51LSB
Eo偏移误差 -0.11LSB
EG增益误差 1LSB
Eo微分非线性误差 0.71.5LSB
E1积 分非线性误差 2LSB
RAIN通道等效电阻
00 ohm
4、ADC相关计算公式
(1)、ADC速度计算公式
ADC的转换速度由ADCCFG寄存器中的SPEED和ADCTIM寄存器共同控制。转换速度的计算公式如下所示:
MCU工作频率SYSclk
12位ADC转换速度=————————————————————————————————————————
2 x (SPEED + 1) x [(CSSETUP + 1) + (CSHOLD + 1) + (SMPDUTY + 1) + 12]
注意:
12位ADC的速度不能高于 800KHz
SMPDUTY的值不能小于10,建议设置为15
CSSETUP可使用上电默认值0
CHOLD可使用上电默认值1(ADCTIM建议设置为3FH)
(2)、ADC转换结果计算公式
ADC被转换通道的输入电压Vin
12位ADC转换结果 = 4096 x ————————————————— (有独立ADC_Vref + 管脚)
ADC外部参考源的电压
(3)、反推ADC输入电压计算公式
12位ADC转换结果
ADC被转换通道的输入电压Vin = ADC外部参考源的电压 x ———————————— (有独立ADC_Vref + 管脚)
4096
(4)、反推工作电压计算公式
当需要使用ADC输入电压和ADC转换结果反推工作电压时,若目标芯片无独立的ADC+Vref + 管脚,则可直接测量并使用下面公式,若目标芯片有独立ADC_Vref + 管脚时,则必须将ADC_Vref + 管脚连接到 Vcc 管脚。
ADC被转换通道的输入电压Vin
MCU工作电压Vcc = 4096 x —————————————————
12位ADC转换结果
5、ADC应用参考线路图
(1)、一般精度ADC参考线路图
(2)、高精度ADC参考线路图
6、 STC—ISP | ADC转换速度计算器工具
首先复制第16讲的“12、IO口中断”的代码,把第16讲的工程复制过来,改名为“13、ADC采集”,在“HARDWARE”文件夹中新建“ADC”文件夹,在文件夹里新建adc.c和adc.h两个文件,adc.c里填写如下程序:
#include "adc.h"
#include "intrins.h"
//=======================================================================
//函数名称:ADC_Init
//函数功能:ADC初始化
//入口参数:
//函数返回:
//当前版本:
//修改日期:
//当前作者:
//其他备注:
//=========================================================================
void ADC_Init(void)
{
P1M0 = 0x00; //设置P10为高阻输入
P1M1 = 0x00;
ADCTIM = 0X3F;
ADCCFG = 0X2F; //数据右对齐,时钟选择位SYSCLK/2/16 最慢
ADC_POWER = 1; //打开adc电源
}
//=======================================================================
//函数名称:ADC_Read
//函数功能:读取指定通道的adc电压
//入口参数:@no :通道0~15
//函数返回:当前的12位adc数值
//当前版本:VER1.0
//修改日期:2023
//当前作者:
//其他备注:
//=========================================================================
u16 ADC_Read(u8 no)
{
u16 adcval; //adc数值保存变量
ADC_CONTR &= 0xf0; //清空通道
ADC_CONTR |= no; //选择通道
ADC_START = 1; //开启ADC转化
_nop_();
_nop_();
while(!ADC_FLAG);
ADC_FLAG = 0;
adcval = (ADC_RES << 8) + ADC_RESL; //计算adc的值
return adcval;
}
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电压
#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#";
bitTIM_10MS_Flag; //10ms的标志位
void sys_init(); //函数声明
void delay_ms(u16 ms); //unsigned int
void main() //程序开始运行的入口
{
u16 ADC_VAL; //ADC的数值
sys_init(); //USB功能+IO口初始化
usb_init(); //usb库初始化
Timer0_Init(); //定时器0初始化
ADC_Init();
EA = 1; //CPU开放中断,打开总中断。
LED = 0xff; //初始状态熄灭所有LED
while(1) //死循环
{
delay_ms(2);
if( DeviceState != DEVSTATE_CONFIGURED ) //
continue;
if( bUsbOutReady )
{
usb_OUT_done();
}
if(TIM_10MS_Flag==1) //如果10ms到了
{
TIM_10MS_Flag = 0; //清空标志位
}
ADC_VAL = ADC_Read(0); //保存ADC的数值
printf("当前ADC数值:%d\r\n\xfd",(int)ADC_VAL); //串口打印ADC数值
}
}
void Timer0_Isr(void) interrupt 1
{
static timcount = 0;
SEG_LED_Show(); //数码管刷新的
timcount++; //1ms+1
if( timcount>=10 ) //如果这个变量大于等于10,10ms计数到达
{
timcount = 0;
TIM_10MS_Flag = 1; //10ms时间到了
}
}
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);
}
编译成功后,0错误0警告,在Objects文件夹中产生Demo.hex文件,下载到STC32G试验箱9.6中,在STCAI-ISP中的串口项目中,能看到ADC的数值。
jason813
发表于 2024-4-29 13:48:57
跟冲哥学stc,最新stc学起来
jason813
发表于 2024-4-29 14:02:04
第一集:30岁+上班也能学 跟着冲哥学一手{:lol:}
jason813
发表于 2024-4-29 14:52:57
第二集:学了第二集了解了 电磁炉,豆浆机都是单片机的应用,继续冲
好学天上
发表于 2024-4-29 17:14:45
第十五集外部中断打卡!!! 这真是激动人心的时刻{:lol:}
STC32G128K芯片学习打卡贴
https://www.stcaimcu.com/forum.php?mod=viewthread&tid=7834
(出处: 国芯技术交流网站)