[STM8] STM8学习笔记---ADC多通道采样

[复制链接]
3308|11
 楼主| lxs0026 发表于 2021-6-22 22:59 | 显示全部楼层 |阅读模式

STM8S003单片机ADC采样通道总共有5个,从AIN2---AIN6,多通道采样时需要将ADC转换设置为单次转换模式,每次切换采样通道后,需要重新初始化 ADC,采样结果在中断中读取。

IO口初始化代码


  1. //AD通道引脚初始化
  2. void ADC_GPIO_Init( void )
  3. {
  4.     PD_DDR &= ~( 1 << 2 );              //PD2 设置为输入     AIN3
  5.     PD_CR1 &= ~( 1 << 2 );              //PD2 设置为悬空输入
  6.    
  7.     PD_DDR &= ~( 1 << 3 );              //PD3 设置为输入      AIN4
  8.     PD_CR1 &= ~( 1 << 3 );              //PD3 设置为悬空输入
  9.    
  10.     PC_DDR &= ~( 1 << 4 );              //PC4 设置为输入      AIN2
  11.     PC_CR1 &= ~( 1 << 4 );              //PC4 设置为悬空输入
  12.    
  13.     PD_DDR &= ~( 1 << 5 );              //PD5 设置为输入     AIN5
  14.     PD_CR1 &= ~( 1 << 5 );              //PD5 设置为悬空输入
  15.    
  16.     PD_DDR &= ~( 1 << 6 );              //PD6 设置为输入     AIN6
  17.     PD_CR1 &= ~( 1 << 6 );              //PD6 设置为悬空输入
  18.    
  19. }


 楼主| lxs0026 发表于 2021-6-22 22:59 | 显示全部楼层
将ADC的IO口都设置为输入模式,悬空输入。
 楼主| lxs0026 发表于 2021-6-22 23:00 | 显示全部楼层
下来初始化ADC功能
  1. void ADC_CH_Init( u8 ch )
  2. {
  3.     char l = 0;
  4.     ADC_CR1  = 0x00;                    //fADC = fMASTER/2, 8Mhz  单次转换,禁止转换
  5.     ADC_CSR  = ch + 1;                  //控制状态寄存器 选择要 AD输入通道  如:PD2(AIN3)
  6.     ADC_CR2  = 0x00;                    //默认左对齐 读数据时先读高在读低
  7.     ADC_TDRL = ( 1 << ( ch + 1 ) );     //禁止相应通道 施密特触发功能 1左移ch+1位
  8.     ADC_CR1 |= 0x01;                    //使能ADC并开始转换
  9.     ADC_CSR |= 0x20;                    //EOCIE 使能转换结束中断  EOC中断使能
  10.     for( l = 0; l < 100; l++ );         //延时,保证ADC模块的上电完成 至少7us
  11.     ADC_CR1 = ADC_CR1 | 0x01;           //再次将CR1寄存器的最低位置1 使能ADC 并开始转换
  12. }
 楼主| lxs0026 发表于 2021-6-22 23:01 | 显示全部楼层
将ADC设置为单次转换模式,每次转换时需要手动将CR1寄存器最低位置1.

在中断中读取转换成功后的数据。
 楼主| lxs0026 发表于 2021-6-22 23:02 | 显示全部楼层
  1. #pragma vector = 24                              // IAR中的中断号,要在STVD中的中断号上加2
  2. __interrupt void ADC_Handle( void )
  3. {
  4.     ADC_CSR &= ~0x80;                            // 转换结束标志位清零  EOC
  5.     //默认左对齐 读数据时先读高高8位 再读低8位
  6.     DATAH = ADC_DRH;                             // 读出ADC结果的高8位
  7.     DATAL = ADC_DRL;                             // 读出ADC结果的低8位
  8.     ADC_flag = 1;                                // ADC中断标志 置1
  9. }
 楼主| lxs0026 发表于 2021-6-22 23:02 | 显示全部楼层
中断中将转换后的采样值存储在DATAH,和DATAL中,并置位采样结束标志位ADC_flag,采样函数判断标志位为1时,就去读取ADC采样值。
 楼主| lxs0026 发表于 2021-6-22 23:03 | 显示全部楼层
采样值读取函数:
  1. //采集PC4电压值  AIN2
  2. u16 ReadVol_CH2( void )
  3. {
  4.     u16 voltage = 0;
  5.     ADC_CH_Init( 1 );
  6.     while( ADC_flag == 0 );
  7.     if( ADC_flag )
  8.     {
  9.         ADC_flag = 0;
  10.         voltage = ( DATAH << 2 ) + DATAL ;        //得到十位精度的数据  0--1024
  11.         //ADC_CR1 = ADC_CR1 | 0x01;               // 再次将CR1寄存器的最低位置1  启动下一次转换
  12.     };
  13.     return voltage;
  14. }
 楼主| lxs0026 发表于 2021-6-22 23:04 | 显示全部楼层
单片机有些引脚的功能需要通过选项字开启,通过ST Visual Programmer软件设置选项字方法如下:
6854660d1fbe26af9e.png
 楼主| lxs0026 发表于 2021-6-22 23:05 | 显示全部楼层
在AFR7中,将选项字中将PC4设置为AIN2功能。
 楼主| lxs0026 发表于 2021-6-22 23:05 | 显示全部楼层
adc完整代码如下:
  1. #include "adc.h"
  2. #include "main.h"

  3. u16  DATAH = 0;                          //ADC转换值高8位
  4. u16  DATAL = 0;                          //ADC转换值低8位
  5. _Bool ADC_flag = 0;                      //ADC转换成功标志


  6. //AD通道引脚初始化
  7. void ADC_GPIO_Init( void )
  8. {
  9.     PD_DDR &= ~( 1 << 2 );              //PD2 设置为输入     AIN3
  10.     PD_CR1 &= ~( 1 << 2 );              //PD2 设置为悬空输入
  11.    
  12.     PD_DDR &= ~( 1 << 3 );              //PD3 设置为输入      AIN4
  13.     PD_CR1 &= ~( 1 << 3 );              //PD3 设置为悬空输入
  14.    
  15.     PC_DDR &= ~( 1 << 4 );              //PC4 设置为输入      AIN2
  16.     PC_CR1 &= ~( 1 << 4 );              //PC4 设置为悬空输入
  17.    
  18.     PD_DDR &= ~( 1 << 5 );              //PD5 设置为输入     AIN5
  19.     PD_CR1 &= ~( 1 << 5 );              //PD5 设置为悬空输入
  20.    
  21.     PD_DDR &= ~( 1 << 6 );              //PD6 设置为输入     AIN6
  22.     PD_CR1 &= ~( 1 << 6 );              //PD6 设置为悬空输入
  23.    
  24. }

  25. //ADC输入通道初始化入口参数表示通道选择
  26. void ADC_CH_Init( u8 ch )
  27. {
  28.     char l = 0;
  29.     ADC_CR1  = 0x00;                    //fADC = fMASTER/2, 8Mhz  单次转换,禁止转换
  30.     ADC_CSR  = ch + 1;                  //控制状态寄存器 选择要 AD输入通道  如:PD2(AIN3)
  31.     ADC_CR2  = 0x00;                    //默认左对齐 读数据时先读高在读低
  32.     ADC_TDRL = ( 1 << ( ch + 1 ) );     //禁止相应通道 施密特触发功能 1左移ch+1位
  33.     ADC_CR1 |= 0x01;                    //使能ADC并开始转换
  34.     ADC_CSR |= 0x20;                    //EOCIE 使能转换结束中断  EOC中断使能
  35.     for( l = 0; l < 100; l++ );         //延时,保证ADC模块的上电完成 至少7us
  36.     ADC_CR1 = ADC_CR1 | 0x01;           //再次将CR1寄存器的最低位置1 使能ADC 并开始转换
  37. }


  38. //采集PC4电压值  AIN2
  39. u16 ReadVol_CH2( void )
  40. {
  41.     u16 voltage = 0;
  42.     ADC_CH_Init( 1 );
  43.     while( ADC_flag == 0 );
  44.     if( ADC_flag )
  45.     {
  46.         ADC_flag = 0;
  47.         voltage = ( DATAH << 2 ) + DATAL ;        //得到十位精度的数据  0--1024
  48.         //ADC_CR1 = ADC_CR1 | 0x01;               // 再次将CR1寄存器的最低位置1  启动下一次转换
  49.     };
  50.     return voltage;
  51. }

  52. //采集PD2电压值  AIN3
  53. u16 ReadVol_CH3( void )
  54. {
  55.     u16 voltage = 0;
  56.     ADC_CH_Init( 2 );
  57.     while( ADC_flag == 0 );
  58.     if( ADC_flag )
  59.     {
  60.         ADC_flag = 0;
  61.         voltage = ( DATAH << 2 ) + DATAL ;
  62.         //ADC_CR1 = ADC_CR1 | 0x01;              //当通道不需要切换时,只需初始化一次,以后每次读取完数据后,需要手动开启下一次转换
  63.     };
  64.     return voltage;
  65. }
  66. //采集PD3电压值  AIN4
  67. u16 ReadVol_CH4( void )
  68. {
  69.     u16 voltage = 0;
  70.     ADC_CH_Init( 3 );
  71.     while( ADC_flag == 0 );
  72.     if( ADC_flag )
  73.     {
  74.         ADC_flag = 0;
  75.         voltage = ( DATAH << 2 ) + DATAL ;       //得到十位精度的数据  0--1024
  76.         //ADC_CR1 = ADC_CR1 | 0x01;              // 再次将CR1寄存器的最低位置1  启动下一次转换
  77.     };
  78.     return voltage;
  79. }

  80. //采集PD5电压值  AIN5
  81. u16 ReadVol_CH5( void )
  82. {
  83.     u16 voltage = 0;
  84.     ADC_CH_Init( 4 );
  85.     if( ADC_flag )
  86.     {
  87.         ADC_flag = 0;
  88.         voltage = ( DATAH << 2 ) + DATAL ; //得到十位精度的数据  0--1024
  89.         //ADC_CR1 = ADC_CR1 | 0x01;          //再次将CR1寄存器的最低位置1  启动下一次转换
  90.     };
  91.     return voltage;
  92. }

  93. //采集PD6电压值  AIN6
  94. u16 ReadVol_CH6( void )
  95. {
  96.     u16 voltage = 0;
  97.     ADC_CH_Init( 5 );
  98.     if( ADC_flag )
  99.     {
  100.         ADC_flag = 0;
  101.         voltage = ( DATAH << 2 ) + DATAL ; //得到十位精度的数据  0--1024
  102.         //ADC_CR1 = ADC_CR1 | 0x01;          //再次将CR1寄存器的最低位置1  启动下一次转换
  103.     };
  104.     return voltage;
  105. }

  106. //AD中断服务函数 中断号22
  107. #pragma vector = 24                              // IAR中的中断号,要在STVD中的中断号上加2
  108. __interrupt void ADC_Handle( void )
  109. {
  110.     ADC_CSR &= ~0x80;                            // 转换结束标志位清零  EOC
  111.     //默认左对齐 读数据时先读高高8位 再读低8位
  112.     DATAH = ADC_DRH;                             // 读出ADC结果的高8位
  113.     DATAL = ADC_DRL;                             // 读出ADC结果的低8位
  114.     ADC_flag = 1;                                // ADC中断标志 置1
  115. }
 楼主| lxs0026 发表于 2021-6-22 23:06 | 显示全部楼层
主函数代码如下:


  1. #include "iostm8s103F3.h"
  2. #include "main.h"
  3. #include "led.h"
  4. #include "adc.h"
  5. #include "delay.h"

  6. u16 val_ch2 = 0, val_ch3 = 0, val_ch4 = 0, val_ch5 = 0, val_ch6 = 0;

  7. void SysClkInit( void )
  8. {
  9.     CLK_SWR = 0xe1;                             //HSI为主时钟源  16MHz CPU时钟频率
  10.     CLK_CKDIVR = 0x00;                          //CPU时钟0分频,系统时钟0分频
  11. }

  12. void main( void )
  13. {
  14.     u8 i=0;
  15.     __asm( "sim" );                             //禁止中断
  16.     SysClkInit();
  17.     delay_init( 16 );
  18.     LED_GPIO_Init();
  19.     ADC_GPIO_Init();
  20.     __asm( "rim" );                             //开启中断
  21.     while( 1 )
  22.     {
  23.         LED = ~LED;
  24.         
  25.         //通道切换后,采样的第一笔数据仍然为上一通道的数据
  26.         for(i=0;i<10;i++)
  27.         val_ch2 = ReadVol_CH2();
  28.         delay_ms( 100 );
  29.         
  30.          for(i=0;i<10;i++)
  31.         val_ch3 = ReadVol_CH3();
  32.         delay_ms( 100 );
  33.         
  34.          for(i=0;i<10;i++)
  35.         val_ch4 = ReadVol_CH4();
  36.         delay_ms( 100 );
  37.         
  38.          for(i=0;i<10;i++)
  39.         val_ch5 = ReadVol_CH5();
  40.         delay_ms( 100 );
  41.         
  42.         for(i=0;i<10;i++)
  43.         val_ch6 = ReadVol_CH6();
  44.         delay_ms( 100 );     
  45.     }
  46. }

打赏榜单

巧克力娃娃 打赏了 1.00 元 2021-06-30
理由:感谢分享

黑心单片机 发表于 2021-6-30 10:18 | 显示全部楼层
困了送枕头,正好需要,多通道ADC采样很常用呀
您需要登录后才可以回帖 登录 | 注册

本版积分规则

103

主题

1290

帖子

1

粉丝
快速回复 在线客服 返回列表 返回顶部