STM8S003单片机ADC采样通道总共有5个,从AIN2---AIN6,多通道采样时需要将ADC转换设置为单次转换模式,每次切换采样通道后,需要重新初始化 ADC,采样结果在中断中读取。
IO口初始化代码
- //AD通道引脚初始化
- void ADC_GPIO_Init( void )
- {
- PD_DDR &= ~( 1 << 2 ); //PD2 设置为输入 AIN3
- PD_CR1 &= ~( 1 << 2 ); //PD2 设置为悬空输入
- PD_DDR &= ~( 1 << 3 ); //PD3 设置为输入 AIN4
- PD_CR1 &= ~( 1 << 3 ); //PD3 设置为悬空输入
- PC_DDR &= ~( 1 << 4 ); //PC4 设置为输入 AIN2
- PC_CR1 &= ~( 1 << 4 ); //PC4 设置为悬空输入
- PD_DDR &= ~( 1 << 5 ); //PD5 设置为输入 AIN5
- PD_CR1 &= ~( 1 << 5 ); //PD5 设置为悬空输入
- PD_DDR &= ~( 1 << 6 ); //PD6 设置为输入 AIN6
- PD_CR1 &= ~( 1 << 6 ); //PD6 设置为悬空输入
- }
将ADC的IO口都设置为输入模式,悬空输入。
下来初始化ADC功能
- 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 并开始转换
- }
将ADC设置为单次转换模式,每次转换时需要手动将CR1寄存器最低位置1.
在中断中读取转换成功后的数据。
- #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
- }
中断中将转换后的采样值存储在DATAH,和DATAL中,并置位采样结束标志位ADC_flag,采样函数判断标志位为1时,就去读取ADC采样值。
采样值读取函数:
- //采集PC4电压值 AIN2
- u16 ReadVol_CH2( void )
- {
- u16 voltage = 0;
- ADC_CH_Init( 1 );
- while( ADC_flag == 0 );
- if( ADC_flag )
- {
- ADC_flag = 0;
- voltage = ( DATAH << 2 ) + DATAL ; //得到十位精度的数据 0--1024
- //ADC_CR1 = ADC_CR1 | 0x01; // 再次将CR1寄存器的最低位置1 启动下一次转换
- };
- return voltage;
- }
单片机有些引脚的功能需要通过选项字开启,通过ST Visual Programmer软件设置选项字方法如下:
在AFR7中,将选项字中将PC4设置为AIN2功能。
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 << 2 ); //PD2 设置为输入 AIN3
- PD_CR1 &= ~( 1 << 2 ); //PD2 设置为悬空输入
- PD_DDR &= ~( 1 << 3 ); //PD3 设置为输入 AIN4
- PD_CR1 &= ~( 1 << 3 ); //PD3 设置为悬空输入
- PC_DDR &= ~( 1 << 4 ); //PC4 设置为输入 AIN2
- PC_CR1 &= ~( 1 << 4 ); //PC4 设置为悬空输入
- PD_DDR &= ~( 1 << 5 ); //PD5 设置为输入 AIN5
- PD_CR1 &= ~( 1 << 5 ); //PD5 设置为悬空输入
- PD_DDR &= ~( 1 << 6 ); //PD6 设置为输入 AIN6
- PD_CR1 &= ~( 1 << 6 ); //PD6 设置为悬空输入
- }
- //ADC输入通道初始化入口参数表示通道选择
- 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 并开始转换
- }
- //采集PC4电压值 AIN2
- u16 ReadVol_CH2( void )
- {
- u16 voltage = 0;
- ADC_CH_Init( 1 );
- while( ADC_flag == 0 );
- if( ADC_flag )
- {
- ADC_flag = 0;
- voltage = ( DATAH << 2 ) + DATAL ; //得到十位精度的数据 0--1024
- //ADC_CR1 = ADC_CR1 | 0x01; // 再次将CR1寄存器的最低位置1 启动下一次转换
- };
- return voltage;
- }
- //采集PD2电压值 AIN3
- u16 ReadVol_CH3( void )
- {
- u16 voltage = 0;
- ADC_CH_Init( 2 );
- while( ADC_flag == 0 );
- if( ADC_flag )
- {
- ADC_flag = 0;
- voltage = ( DATAH << 2 ) + DATAL ;
- //ADC_CR1 = ADC_CR1 | 0x01; //当通道不需要切换时,只需初始化一次,以后每次读取完数据后,需要手动开启下一次转换
- };
- return voltage;
- }
- //采集PD3电压值 AIN4
- u16 ReadVol_CH4( void )
- {
- u16 voltage = 0;
- ADC_CH_Init( 3 );
- while( ADC_flag == 0 );
- if( ADC_flag )
- {
- ADC_flag = 0;
- voltage = ( DATAH << 2 ) + DATAL ; //得到十位精度的数据 0--1024
- //ADC_CR1 = ADC_CR1 | 0x01; // 再次将CR1寄存器的最低位置1 启动下一次转换
- };
- return voltage;
- }
- //采集PD5电压值 AIN5
- u16 ReadVol_CH5( void )
- {
- u16 voltage = 0;
- ADC_CH_Init( 4 );
- if( ADC_flag )
- {
- ADC_flag = 0;
- voltage = ( DATAH << 2 ) + DATAL ; //得到十位精度的数据 0--1024
- //ADC_CR1 = ADC_CR1 | 0x01; //再次将CR1寄存器的最低位置1 启动下一次转换
- };
- return voltage;
- }
- //采集PD6电压值 AIN6
- u16 ReadVol_CH6( void )
- {
- u16 voltage = 0;
- ADC_CH_Init( 5 );
- 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
- }
主函数代码如下:
- #include "iostm8s103F3.h"
- #include "main.h"
- #include "led.h"
- #include "adc.h"
- #include "delay.h"
- u16 val_ch2 = 0, val_ch3 = 0, val_ch4 = 0, val_ch5 = 0, val_ch6 = 0;
- void SysClkInit( void )
- {
- CLK_SWR = 0xe1; //HSI为主时钟源 16MHz CPU时钟频率
- CLK_CKDIVR = 0x00; //CPU时钟0分频,系统时钟0分频
- }
- void main( void )
- {
- u8 i=0;
- __asm( "sim" ); //禁止中断
- SysClkInit();
- delay_init( 16 );
- LED_GPIO_Init();
- ADC_GPIO_Init();
- __asm( "rim" ); //开启中断
- while( 1 )
- {
- LED = ~LED;
- //通道切换后,采样的第一笔数据仍然为上一通道的数据
- for(i=0;i<10;i++)
- val_ch2 = ReadVol_CH2();
- delay_ms( 100 );
- for(i=0;i<10;i++)
- val_ch3 = ReadVol_CH3();
- delay_ms( 100 );
- for(i=0;i<10;i++)
- val_ch4 = ReadVol_CH4();
- delay_ms( 100 );
- for(i=0;i<10;i++)
- val_ch5 = ReadVol_CH5();
- delay_ms( 100 );
- for(i=0;i<10;i++)
- val_ch6 = ReadVol_CH6();
- delay_ms( 100 );
- }
- }
联系客服