在使用STM8单片机的ADC功能时,读取ADC数据时一般有两种方式,一种是通常不断地读取采样标志位,来判断ADC采样是否结束,一种是通过中断的方式来通知系统采样是否结束。
有时候采样ADC数据的时候,需要按照一定的时间间隔,定点的去采样数据。一般使用的方式就是通过定时器定时,然后在定时中断函数中再去读取ADC采样的数据。但是这种方式采样的时间是不固定的,比如进入定时器中断后,ADC采样刚结束,就可以直接使用当前采样到的数据。但是如果运气不好的话,进入定时中断后,ADC采样刚开始,那么此时就需要等到ADC采样结束后,才能使用数据。这样就好导致每次读取ADC数据时还会有随机的一段等到ADC数据的延时。
通常查阅STM8单片机的手册发现,ADC采样可以通过定时器来触发。
通过定时器来触发ADC采样时,定时器的定时时间是固定的,采样时间也是固定的,这样采样数据的间隔也就是固定的。这样通过定时器来触发ADC的采样时间,就能完全保证每次读取ADC采样数据的时间间隔都是一样的,从而避免了数据的误差。
数据手册中对于开启ADC触发功能描述如下:
对于如何通过代码来设置ADC触发,官方也没有详细的说明,在网上也没有找到相关例程。所以只能自己摸索,还好通过自己的一番摸索,成功的通过定时器的TRGO事件触发了ADC的启动。
关于ADC相关寄存器的设置,基本就是上面说的6条。接下来需要设置的就是定时器的相关寄存器。
关于定时器只需要设置CR2寄存器中的 MMS位就可以了。
接下来就通过代码来实现。
#include "adc.h"
#include "main.h"
#include "led.h"
u16 DATAH = 0; //ADC转换值高8位
u16 DATAL = 0; //ADC转换值低8位
_Bool ADC_flag = 0; //ADC转换成功标志
u16 adc_cnt = 0;
//AD通道引脚初始化
void ADC_GPIO_Init( void )
{
PD_DDR &= ~( 1 << 2 ); //PD2 设置为输入
PD_CR1 &= ~( 1 << 2 ); //PD2 设置为悬空输入
PD_DDR &= ~( 1 << 3 ); //PD3 设置为输入
PD_CR1 &= ~( 1 << 3 ); //PD3 设置为悬空输入
}
//ch 为单片机的ADC 通道
//ADC输入通道初始化入口参数表示通道选择
void ADC_CH_Init( u8 ch )
{
char l = 0;
ADC_CR1 = 0x00; //fADC = fMASTER/2, 8Mhz 单次转换,禁止转换
ADC_CR2 = 0x00; //默认左对齐 读数据时先读高在读低
ADC_CR2 |= ( 1 << 6 ); //外部触发使能
ADC_CSR |= ch; //控制状态寄存器 选择要 AD输入通道 如:PD2(AIN3)
ADC_TDRL = ( 1 << ch ); //禁止相应通道 施密特触发功能 1左移ch位
ADC_CR1 |= 0x01; //使能ADC并开始转换
ADC_CSR |= ( 1 << 5 ); //EOCIE 使能转换结束中断 EOC中断使能
for( l = 0; l < 100; l++ ); //延时,保证ADC模块的上电完成 至少7us
ADC_CR1 = ADC_CR1 | 0x01; //再次将CR1寄存器的最低位置1 使能ADC 并开始转换
}
u16 value = 0;
//AD中断服务函数 中断号22
#pragma vector = 24 // IAR中的中断号,要在STVD中的中断号上加2
__interrupt void ADC_Handle( void )
{
ADC_CSR &= ~0x80; // 转换结束标志位清零 EOC
//默认左对齐 读数据时先读高高8位 再读低8位
DATAH = ADC_DRH; // 读出ADC结果的高8位
DATAL = ADC_DRL; // 读出ADC结果的低8位
ADC_flag = 1; // ADC中断标志 置1
value = ( DATAH << 2 ) + DATAL ; //得到十位精度的数据 0--1024
adc_cnt++;
LED = !LED;
}
在ADC代码中,相比普通的ADC初始化方式,这里只需要增加一句对ADC_CR2寄存器的设置。
ADC_CR2 |= ( 1 << 6 ); //外部触发使能
在ADC_CR2寄存器中 使能外部触发转换功能,设置外部触发事件为 内部定时器1 TRG事件。
这里ADC使用的是单次触发模式,开启外部触发功能,开启ADC转换中断,当ADC转换完成之后,就会进入到ADC中断中,在中断中读取采样的数据,然后翻转LED的状态,通过示波器观察LED引脚电平的变化,就可以知道ADC中断进入的频率了。
接下来编写定时器初始化代码。
unsigned long time_cnt = 0;
// 使用 定时器触发 ADC采样
void tim1_init( void )
{
TIM1_ARRH = ( unsigned char )( 1000 >> 8 ); //定时1ms
TIM1_ARRL = ( unsigned char )( 1000 );
TIM1_PSCRH = ( unsigned char )( 0x0F >> 8 ); // 16M / (1+15) =1M
TIM1_PSCRL = ( unsigned char )( 0x0F );
TIM1_RCR = 0x00; //重复计数器值
TIM1_SR1 = ( ~0x01 ); //清除更新中断标志
TIM1_CR2 |= ( 2 << 4 ); //使能信号,用于触发输出(TRGO)
TIM1_CR1 |= 0x01; //使能计数器
TIM1_IER |= 0x01; //更新中断使能
}
#pragma vector = 13 //IAR中的中断号,要在STVD中的中断号上加2
__interrupt void Timer1_Handle( void ) //1ms 定时中断
{
TIM1_SR1 = ( ~0x01 ); //清除更新中断标志
time_cnt++;
}
定时器的初始化代码,也比正常情况下初始化代码多了一行。
TIM1_CR2 |= ( 2 << 4 ); //使能信号,用于触发输出(TRGO)
用来开启定时的的TRG功能。
经过测试,这里定时器CR2寄存器中的值 只能设置为 010 或者 011,设置为其他值时,不能触发ADC采样。最开始测试的时候按照芯片资料上这个说明,MMS的值设置的是 001,ADC总是触发不了,还以为是方法的问题,最后才发现是MMS值设置的问题。
ADC和定时器初始化代码设置完成之后,接下来在主函数中初始化这两个函数就行了,按照资料上说的,首先初始化完ADC之后,再初始化定时器。
void main( void )
{
__asm( "sim" ); //禁止中断
SysClkInit();
delay_init( 16 );
LED_GPIO_Init();
ADC_GPIO_Init();
ADC_CH_Init(3);
tim1_init();
__asm( "rim" ); //开启中断
while( 1 )
{
}
}
接下来运行程序。
分别在ADC中断中和定时器中断中用一个变量来统计中断执行的次数,通过变量变量观察窗口可以看到,ADC中断的次数比定时器中断的次数多了1次。这是因为ADC在初始化的时候,已经运行了一次。
然后通过示波器观察LED口的电平。
定时器的定时时间是1ms,LED的高低电平时间也是1ms,说明通过定时器触发ADC采样功能是正常运行的。
为了减小系统进入中断的次数,可以将定时器的中断功能关闭掉。定时器中断功能关闭后,ADC的触发功能依然可以正常使用。
这样只需要开启一个ADC中断,再加上定时器的TRG触发功能后,就可以实现ADC定时采样的功能了。
上一篇:STM8单片机通过PWM触发ADC同步采样
下一篇:单片机快速将库函数版代码移植为寄存器代码方法
推荐阅读





推荐帖子
- 印制电路板的电磁兼容性
- 电路的合理布局 地线的设计 信号走线的设计 线路板层数的选择 器件的安排 PCB的EMC分析基本定律 克希霍夫定律:任何时域信号由源到负载的传输都必须构成一个完 整的回路,一个频域信号由源到负载的传输都必须有一个 最低阻抗的路径。 印制电路板的电磁兼容性
-
czf0408
LED专区
- 看maychang“整流杂谈”,学习整流知识
- 看maychang“整流杂谈”,大家一起来学习整流知识吧~~ [index] [#483778,1981397]整流杂谈(一) [#484435,1985100]整流杂谈(二) [#484851,1987685]整流杂谈(三) [#486297,1996348]整流杂谈(四) [#521937,2138147]整流杂谈(五) [#536154,2180222]整流杂谈(六) [/index] 看maychang“整流杂谈”,学习整流知识
-
okhxyyo
电源技术
- 20种常用模拟电路
- 本帖最后由paulhyde于2014-9-1509:08编辑20常用的模拟电路,大家捧个场啊 20种常用模拟电路
-
非雪之悠
电子竞赛
- 用mega16+L298N驱动直流电机遇到的问题
- 我在制作一个遥控小车。负责无线通信的是24L01,MEGA16为主控芯片,PWM信号经过与非门驱动L298控制直流电机。24L01的程序应经调试成功。现在的问题是接通启动电机,会对MEGA16的IO口产生影响,貌似有某种规律的杂波,并且对24L01的数据读写造成影响,不能正常工作。可是,事实是电机,L298与单片机之间即使只是共地,还是会有这样。电机不工作的时候,都是很正常的。搞不懂。请问哪位大哥做过这方面的东西,指教一下。应该如何改正?用mega16+L298N驱动直流电机遇到的问题
-
hy5239
RF/无线
- 逆变资料
- 本帖最后由paulhyde于2014-9-1503:03编辑给大家传个逆变资料哦 呵呵 逆变资料
-
beautygj
电子竞赛
- art格式的gerber转换成PCB文件
- 再百度上找了些教程,按照上面说的,AD中新建CAM文件,导入文化和钻孔文件,结果钻孔文件和走线的文件都不重合了,就不知道怎么做了,求指导art格式的gerber转换成PCB文件
-
麻袋
PCB设计