历史上的今天
今天是:2024年09月16日(星期一)
2021年09月16日 | STM8单片机ADC单次采样模式
2021-09-16 来源:eefocus
STM8S003单片机内部ADC为12位,A/D转换的各个通道可以执行单次和连续的转换模式。
单次转换模式的意思就是,ADC每次转换一次数据后,就会停止转换,如果还需要继续转换的话,就需要手动开启第二次转换功能。
连续转换模式的意思就是每次转换结束后,系统会自动开启第二次转换,不需要手动设置第二次转换的开启,也就是说连续转换模式只需要开启一次。
ADC框图如下:

ADC转换时序图如下:

下面用代码来实现ADC的单次转换模式:
#include "adc.h"
#include "main.h"
u16 DATAH = 0; //ADC转换值高8位
u16 DATAL = 0; //ADC转换值低8位
_Bool ADC_flag = 0; //ADC转换成功标志
//AD通道引脚初始化
void ADC_GPIO_Init( void )
{
PD_DDR &= ~( 1 << 3 ); //PD3 设置为输入 电流
PD_CR1 &= ~( 1 << 3 ); //PD3 设置为悬空输入
}
//ch 为单片机的对应管脚
void ADC_CH_Init( u8 ch )
{
char l = 0;
ADC_CR1 = 0x00; //fADC = fMASTER/2, 8Mhz 单次转换,禁止转换
ADC_CSR = ch + 1; //控制状态寄存器 选择要 AD输入通道 如:PD2(AIN3)
ADC_CR2 = 0x00; //默认左对齐 读数据时先读高在读低
ADC_TDRL = ( 1 << ( ch + 1 ) ); //禁止相应通道 施密特触发功能 1左移ch+1位
ADC_CR1 |= 0x01; //使能ADC并开始转换
ADC_CSR |= 0x20; //EOCIE 使能转换结束中断 EOC中断使能
for( l = 0; l < 100; l++ ); //延时,保证ADC模块的上电完成 至少7us
ADC_CR1 = ADC_CR1 | 0x01; //再次将CR1寄存器的最低位置1 使能ADC 并开始转换
}
//采集PD3电压值
u16 ReadVol_CH3( void )
{
u16 voltage = 0;
if( ADC_flag )
{
ADC_flag = 0;
voltage = ( DATAH << 2 ) + DATAL ; //得到十位精度的数据 0--1024
ADC_CR1 = ADC_CR1 | 0x01; //再次将CR1寄存器的最低位置1 启动下一次转换
};
return voltage;
}
//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
}
在第一次ADC启动时需要一个稳定时间,所以在初始化的时候,需要一定的时间等待ADC稳定,稳定之后就可以开始ADC转换了,这里使用中断来读取转换结果,当ADC转换换成后就会产生一个中断,然后在中断中读取转换的结果,同时设置标志位。程序循环去读取标志位,当标志位为1时,就说明转换完成了,这时候就可以输出转换的结果了。然后将ADC_CR1寄存器的最低位,手动置1,开启下一次转换。
ADC_CR1寄存器如下:

ADON位就是ADC的转换开关,在单次模式下给ADON位写1就可开启转换。
这里只使用了一个通道,通过最上面ADC框图可以看出,一个ADC中有好多个通道,那么如果要采集多个通道要如何做呢?
#include "adc.h"
#include "main.h"
u16 DATAH = 0; //ADC转换值高8位
u16 DATAL = 0; //ADC转换值低8位
_Bool ADC_flag = 0; //ADC转换成功标志
//AD通道引脚初始化
void ADC_GPIO_Init( void )
{
PD_DDR &= ~( 1 << 3 ); //PD3 设置为输入 电流
PD_CR1 &= ~( 1 << 3 ); //PD3 设置为悬空输入
}
//ch 为单片机的对应管脚
void ADC_CH_Init( u8 ch )
{
char l = 0;
ADC_CR1 = 0x00; //fADC = fMASTER/2, 8Mhz 单次转换,禁止转换
ADC_CSR = ch + 1; //控制状态寄存器 选择要 AD输入通道 如:PD2(AIN3)
ADC_CR2 = 0x00; //默认左对齐 读数据时先读高在读低
ADC_TDRL = ( 1 << ( ch + 1 ) ); //禁止相应通道 施密特触发功能 1左移ch+1位
ADC_CR1 |= 0x01; //使能ADC并开始转换
//ADC_CSR |= 0x20; //EOCIE 使能转换结束中断 EOC中断使能
for( l = 0; l < 100; l++ ); //延时,保证ADC模块的上电完成 至少7us
ADC_CR1 = ADC_CR1 | 0x01; //再次将CR1寄存器的最低位置1 使能ADC 并开始转换
}
//采集PD3电压值
u16 ReadVol_CH3( void )
{
u16 voltage = 0;
//只在程序初始化时调用一次的话,采样速度非常快。
//如果每次都调用初始化,速度将会是原来的 1/10
ADC_CH_Init( 3 );
while( ( ADC_CSR & 0x80 ) == 0 ); //等待转换结束
if( ADC_CSR & 0x80 )
{
DATAH = ADC_DRH; // 读出ADC结果的高8位
DATAL = ADC_DRL; // 读出ADC结果的低8位
voltage = ( DATAH << 2 ) + DATAL ; //得到十位精度的数据 0--1024
ADC_CR1 = ADC_CR1 | 0x01; //再次将CR1寄存器的最低位置1 启动下一次转换
ADC_CSR &= 0x7F;
};
return voltage;
}
//采集PD2电压值
u16 ReadVol_CH4( void )
{
u16 voltage = 0;
//只在程序初始化时调用一次的话,采样速度非常快。
//如果每次都调用初始化,速度将会是原来的 1/10
ADC_CH_Init( 2 );
while( ( ADC_CSR & 0x80 ) == 0 ); //等待转换结束
if( ADC_CSR & 0x80 )
{
DATAH = ADC_DRH; // 读出ADC结果的高8位
DATAL = ADC_DRL; // 读出ADC结果的低8位
voltage = ( DATAH << 2 ) + DATAL ; //得到十位精度的数据 0--1024
ADC_CR1 = ADC_CR1 | 0x01; //再次将CR1寄存器的最低位置1 启动下一次转换
ADC_CSR &= 0x7F;
};
return voltage;
如果需要转换多个通道,那么在一个通道转换完成之后,就需要重新初始化,进行转换通道的切换。由于切换通道后,ADC需要稳定时间,所以如果是多个通道来回切换采样数据的话,比一个通道单独采样数据就要慢很多,因为切换一次通道就需要等待一段时间让ADC稳定。
读取数据时,直接在主函数中调用对应的函数就行。
#include "iostm8s103F3.h"
#include "led.h"
#include "adc.h"
#include "stdio.h"
void SysClkInit( void )
{
CLK_SWR = 0xe1; //HSI为主时钟源 16MHz CPU时钟频率
CLK_CKDIVR = 0x00; //CPU时钟0分频,系统时钟0分频
}
void main( void )
{
u16 val1 = 0;
u16 i=0;
SysClkInit();
__asm( "sim" ); //禁止中断
LED_GPIO_Init();
ADC_CH_Init( 3 );
__asm( "rim" ); //开启中断
while( 1 )
{
LED = !LED;
val1 = ReadVol_CH3();
}
}
上一篇:STM8单片机ADC连续采样模式
史海拾趣
|
我看FPGA现在难以取代FPGA+DSP的架构,这段时间的思索总结 FPGA现在越做越大了,有些公司如Xilinx推出的FPGA都内嵌了DSP核,很多人都在讨论说FPGA会取代现在主流的复杂数字信号处理系统的架构:FPGA+DSP了,SOC片上系统的时代真的要来了,我也对这个概念很憧憬,但经过一段时间的调研后,觉得现在还不成熟, ...… 查看全部问答> |
|
求助:wince socket 蓝牙编程中怎样用OBEX协议封装数据 我是刚接触蓝牙开发的,最近要做一个蓝牙文件传输的应用,就是实现蓝牙设备之间的文件传输, MSDN上研究过SOCKET实现的API函数,但是不知道连接成功后发送的数据怎样才能让对方识别, 网上有人说\"这些数据必须是经过OBEX协议封装好的数据\" 请做过这 ...… 查看全部问答> |
|
各位大侠:你们好! 最近,我在刚做好的一块DSP2407A板上试调程序,不知道为什么程序运行后无法进入中断.我只是编了一个非常简单的小程序,用定时器控制LCD闪烁.整个程序我检察了好多遍,应该没有问题的,但就是无法进入中断子 ...… 查看全部问答> |
|
【视频分享】电源设计小贴士49:多层陶瓷电容器常见小缺陷的规避方法 各位好久不见啦!!最近美女小编感冒了,在家休息,有好一阵子没和大家分享好的东东啦! 今天和大家分享TI电源设计小贴士系列的视频,讲解得十分透彻。 因其小尺寸、低等效串联电阻(ESR)、低成本、高可靠性和高纹波电流能力,多层陶瓷 (MLC) 电容 ...… 查看全部问答> |
|
SSI2.DLL是wince里面的一个动态链接库,主要作用是调动设备中的激光扫描头,由于本人不会编程,特此求助附件是相应的.H和.LIB文件,说明文档还有示例文件,希望可以得到帮助,帮忙生成DLL文件 … 查看全部问答> |




