今天我们来看看ADC。
不是你游戏里的ADC哈,是模拟到数字转换器(Analog-to-Digital Converter)
STC32G12k128的ADC是12位分辨率,有15个通道。
但是遗憾的是我们的STC8G1K08A-SOP8的这款没有ADC。不过STC8G1K08A的其他封装的有,虽然只有10位六通道吧。
所以我们还是主要讲讲STC32的ADC。
讲ADC之前我们还要谈谈Vref,基准电压源。
如果芯片有这个引脚的话,我们最好是给Vref接个2.5V的基准电压源,实在不行就直接接VCC,反正不能悬空。
开源自己设计的STC核心板,集成STC32和STC8一次性学习两款芯片-CSDN博客文章浏览阅读911次,点赞23次,收藏19次。官方提供的最小系统图也就是俩电容,一个10uf以上,一个100nf,虽然说10uf以上,但是10uf应该也可以,我是因为手头上22uf的电容比较多,所以用的22uf,大家也可以根据自己的库存去决定,反正打板出来焊盘大小都是一样的,一样封装的都是可以随便替换。一个STC8G1K08A-SOP8的官方推荐零售价是0.59 + 0.1,所以小伙伴们买的时候注意价格,我买的时候是0.75,因为价格差的不多并且是从经常买的店铺里卖的,所以就不管这点差价了,总之大家买的时候别买价格太离谱的。_stc32和stc8https://blog.csdn.net/m0_63235356/article/details/144374813?spm=1001.2014.3001.5501我用的是之前开源的板子,有个2.5V的基准电压源,如果我们手上的板子没有2.5V的基准电压源,那么计算公式是不一样的,这边要注意一下。
然后ADC实际上是有16个通道,但是最后一个是内部固定的1.19V,所以我们能用的是15个通道。
这个1.19V的作用就是假设我们ADC15读出来的值是x,而其他某通道读出的是y。
我们知道不管这个x是多少,它代表的就是1.19V,所以某通道的电压就是(1.19V*y)/x
ADC转换的公式如下。
看起来有点复杂,但等等我们一边看这个公式一边看库函数就不复杂了。
ADC的转换公式如下。
上面的ADC外部参考源的电压就是Vref接的基准电压源,记得要根据自己Vref接的电压来改变计算公式。
也就是说我们ADC的电压范围就是0~Vref的电压,Vref接2.5V和Vref接5V之间精度的差别就是两倍,因为12位ADC一共就4096个数,拿4096来表示0~2.5V肯定就比拿4096去表示0~5V要更精确。
接下来看看库函数。
我们首先需要把这个文件STC32G_ADC.c加入工程里。
接下来使用下面这个函数来配置ADC。
配置用的结构体的成员都是我们上面ADC转换时间公式里出现过的。
第一个SMPduty表示ADC采样时间,范围是0~31,但是绝不能小于10,官方推荐是15,但是采样时间越长精度越高,所以我们直接拉满,填上31。
第二个Speed实际上是选择ADC工作的时钟频率,其实是选择系统时钟给ADC提供脉冲时分频的系数,可以是0~15,因为在寄存器中它是占4个bit。结合上面的公式,不管我们填多少,都先是2分频,然后再分频(Speed+1)。
也可以选择宏定义来赋值,大家看直接填数字好还是填宏定义好,挑自己喜欢的来就行。
第四个CsSetup是ADC通道选择时间控制,取值是0或1,其实还是控制ADC转换速度的,默认是0,所以我们就填0。
第五个CsHold是ADC通道选择保持时间控制,取值范围是0~3,默认选择1。
需要注意的是ADC转换时间不能超过800kHz
配置完之后就使能ADC。
使能完ADC之后需要等待1ms,等待ADC内部电源稳定下来。
接着就可以读取ADC的转换结果了,参数传入通道,0~15,通道15固定是内部的1.19V。
如果读出来的是4096,那么就表示发生错误,也就是说只有返回值小于4096的时候我们才能用ADC的转换结果。
记得把对应的GPIO口设置为高阻输入模式。
我下面示例代码中用串口3来打印转换结果的数据,小伙伴们可以看看上一篇文章,因为有些地方要修改的上一篇里都有,我这里就不赘述了。
我用的串口3的P00和P01口作为串口的TXD和RXD,这会占用ADC的俩通道,我这边是测试一下,小伙伴们使用的时候记得不要冲突了。
#include "STC32G_GPIO.h"
#include "STC32G_Delay.h"
#include "STC32G_UART.h"
#include "STC32G_NVIC.h"
#include "STC32G_Switch.h"
#include "STC32G_ADC.h"
void GPIO_Init(void){
P0_MODE_IN_HIZ(GPIO_Pin_2);
P0_MODE_IN_HIZ(GPIO_Pin_3);
P0_MODE_IN_HIZ(GPIO_Pin_4);
P0_MODE_IN_HIZ(GPIO_Pin_5);
P0_MODE_IN_HIZ(GPIO_Pin_6);
// 开几个意思意思.
}
void UART_Init(void){
COMx_InitDefine initer;
initer.BaudRateDouble = DISABLE;
initer.Morecommunicate = DISABLE;
initer.UART_BaudRate = 115200;
initer.UART_BRT_Use = BRT_Timer3;
initer.UART_Mode = UART_8bit_BRTx;
initer.UART_RxEnable = ENABLE;
UART_Configuration(UART3, &initer);
NVIC_UART3_Init(ENABLE, Priority_1);
P0_MODE_IO_PU(GPIO_Pin_0);
P0_MODE_IO_PU(GPIO_Pin_1);
UART3_SW(UART3_SW_P00_P01);
}
void ADC_Init(void){
ADC_InitTypeDef initer;
initer.ADC_AdjResult = ADC_RIGHT_JUSTIFIED; // 右对齐
initer.ADC_CsHold = 1; // 按照默认的来
initer.ADC_CsSetup = 0; // 按照默认的来
initer.ADC_SMPduty = 31; // 最大的采样时间
initer.ADC_Speed = ADC_SPEED_2X8T; // 折中一下
ADC_Inilize(&initer);
ADC_PowerControl(ENABLE);
NVIC_ADC_Init(DISABLE, Priority_0); // 不使用中断
delay_ms(1); // 等待内部电源稳定
}
void main(void){
uint8 i;
WTST = 0; //设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
EAXSFR(); //扩展SFR(XFR)访问使能
CKCON = 0; //提高访问XRAM速度
UART_Init();
GPIO_Init();
ADC_Init();
EA = 1;
while(1){
for(i = 0; i < 16; ++i){
printf("ADC%d is %d\r\n",i,Get_ADCResult(i));
}
delay_ms(1000);
}
return ;
}
通道15的转换结果是1948 +- 1 这样。