找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 16789|回复: 5
收起左侧

STM8L的ADC之测量外部电压(使用了DMA)

[复制链接]
ID:140343 发表于 2016-10-9 23:58 | 显示全部楼层 |阅读模式
本帖最后由 51hei小林 于 2016-10-9 23:59 编辑

之前介绍ADC时,是用ADC测量内部1.225V的参考电压,通过这个参考电压的转化值反推参考电压的实际值.这里要注意,我说的内部参考电压和参考电压是两个不同的概念,内部参考电压就是内部的一个1.225V基准电压,这个电压比较准确,不会受外接干扰,其值也不会改变,一直是1.225V.在STM8L里,这个电压作为一个独立的通道,可以连接到ADC中,供ADC采样,校准自己的参考电压,也可以连接到STM8L的内部比较器的输入端作为一个基准电压,还可以通过引脚输出这个电压. 参考电压,是Vref+和Vref-引脚之间的电压,这个电压是外部的,会随着外部电压的变化而变化,在ADC采样时,这个电压是采样时的参考电压. 上次的例程根据比例关系:

(参考电压/4096)=(内部参考电压/内部参考电压转换值)
已经求出了参考电压的值为2.99V,好吧上次测的其实是2.98V,今天用万用表量了下,是2.99V.为了这次程序的采集数据的准确,还是用2.99V.

本例程和上次的ADC测量内部参考电压例程,并没有太大却别,只是增加了DMA部分.原以为,采样内部通道和外部通道会有很大区别,实际上,只要选择一下采样的外部通道,同时关闭对应的施密特触发器,其余程序和上次一样就可以了.也不需要去设置引脚的输入输出状态,保持默认就行.
使用DMA将ADC转换后的数据传输到一个数组中,本例程采样9次数据,传输完9次数据后会产生一个传输完成中断,在中断中求9次的和,计算平均值,同时计算采样的电压.
DMA的四个通道都可以作为ADC传输数据通道,我们需要使用SYSCFG_RMPCR1这个寄存器来设置具体使用的通道.本例程使用DMA的通道一来传输数据.

在本例程中,仍然使用IAR强大的查看变量功能,进行数据的显示,没有使用板子上的LCD液晶屏,主要原因是为了程序简单,其实是因为我比较懒.本来对数据的处理应该进行滤波处理的,我也仅仅简单的算了下9次采样的平均值,起不到平滑数据的作用,ADC采样的数据确实每次都不一样,软件滤波很重要.
在IAR查看变量,如果变量不是全局变量,在Live Watch窗口或Watch窗口中是看不到数据的,所以只好把这个变量声明为局部静态变量,同样可以显示出数值.
下图是实际的硬件连接图,用来一个电位器,三个脚分别连接到板子的VDD,GND,PD5脚,具体连接是:电位器两边的脚接VDD,GND,中间接PD5.


  1. /*硬件连接*/

  2. // PD5(ADC1_IN9) <----

  3. /****************************************************************************************

  4. *开发环境:IAR for stm8 v1.40.1

  5. *硬件平台:STM8L-DISCOVERY

  6. *功能说明:测量ADC通道9的外部电压,通道9对应的引脚为PD5,在此引脚接了一个电位器,用于输出一个

  7. *        可变的电压,提供给ADC测量

  8. *作    者:茗风

  9. ****************************************************************************************/

  10. #include"iostm8l152c6.h"

  11. #include"stdbool.h"

  12. #include"stdint.h"

  13. #define  ADC_DRH_ADRESS     0x5344

  14. uint16_t  ui16RX_buffer[9]={0};

  15. /******************************************************************************************************

  16. *  名    称:void delay_10ms(uint8_t x_ms)

  17. *  功    能:延时10ms

  18. *  入口参数:无

  19. *  出口参数:无

  20. *  说    明:

  21. *  范    例:无

  22. ******************************************************************************************************/

  23. void delay_100ms(void)

  24. {

  25.   uint8_t i,j;

  26.   for(i=0;i<255;i++)//2*255个指令周期

  27.     for(j=0;j<255;j++);//2*255个指令周期

  28.   //delay_10ms共消耗 x_ms*2*255+2*x_ms个指令周期  

  29.   //255*2*255+2*255=130610us=130ms

  30.   //此延时函数,延时时间为130ms

  31.   //16M/8/2=1M 一个指令周期为1us

  32. }

  33. /******************************************************************************************************

  34. *  名    称:void GPIO_Init(void)

  35. *  功    能:初始化PC7为高速推挽输出

  36. *  入口参数:无

  37. *  出口参数:无

  38. *  说    明:

  39. *  范    例:无

  40. ******************************************************************************************************/

  41. void GPIO_Config(void)

  42. {

  43.    PC_CR1_C17  =1;//推挽输出

  44.    PC_CR2_C27  =1;//高速输出

  45.    PC_DDR_DDR7 =1;//PC7输出

  46.    PC_ODR_ODR7 =0;//输出低电平

  47. }

  48. /******************************************************************************************************

  49. *  名    称:void ADC_Init(void)

  50. *  功    能:初始化ADC

  51. *  入口参数:无

  52. *  出口参数:无

  53. *  说    明:ADC1的测量通道为ADC1_IN9,单次转换模式

  54. *  范    例:无

  55. ******************************************************************************************************/

  56. void ADC_Init(void)

  57. {   

  58.    CLK_PCKENR2_PCKEN20=1; //国际惯例,开启ADC1外设时钟


  59.    ADC1_CR1_ADON=1;  //wakes up the ADC from Power down mode.

  60.    ADC1_CR2_PRESC=1;//Select a sample time of 10 μs

  61. //   0: f(ADC_CLK) = CK

  62. //   1: f(ADC_CLK) = CK/2  //系统时钟此时为默认的16M/8=2M,这里分频后,fadc=2M/2=1M

  63.    

  64.    ADC1_SQR1_DMAOFF=0;    //使能DMA

  65.    

  66.    ADC1_CR3_SMTP2=0x06;//采样时间为24 ADC clock cycles,也就是24*1us=24us

  67. //000: 4 ADC clock cycles

  68. //001: 9 ADC clock cycles

  69. //010: 16 ADC clock cycles

  70. //011: 24 ADC clock cycles

  71. //100: 48 ADC clock cycles

  72. //101: 96 ADC clock cycles

  73. //110: 192 ADC clock cycles

  74. //111: 384 ADC clock cycles

  75.    ADC1_SQR3_CHSEL_S9=1; //选择通道9

  76.    ADC1_TRIGR3_TRIG9=1;  //关闭通道9的施密特触发器

  77. //   ADC1_CR1_EOCIE=1;

  78. }

  79. /******************************************************************************************************

  80. *  名    称:void DMA_Config(void)

  81. *  功    能:启用DMA

  82. *  入口参数:无

  83. *  出口参数:无

  84. *  说    明:

  85. *  范    例:无

  86. ******************************************************************************************************/

  87. void DMA_Config(void)

  88. {

  89.   //------打开DAM时钟------

  90.   CLK_PCKENR2_PCKEN24=1;

  91.   

  92.   //----设置ADC的DMA通道----

  93.   SYSCFG_RMPCR1_ADC1DMA_REMAP=1;

  94. /*  00: ADC1 DMA request/acknowledge mapped on DMA1 channel 0

  95.     01: ADC1 DMA request/acknowledge mapped on DMA1 channel 1

  96.     10: ADC1 DMA request/acknowledge mapped on DMA1 channel 2

  97.     11: ADC1 DMA request/acknowledge mapped on DMA1 channel 3 */

  98.   

  99.   //------设置传送的字节数,------

  100.   DMA1_C1NDTR=9;  

  101.   

  102.   //------设置通道优先级------

  103.   DMA1_C1SPR_PL0=0;DMA1_C1SPR_PL1=1;


  104.   //------设置传送方向------

  105.   DMA1_C1CR_DIR=0;  

  106. /*  0: Transfer from the peripheral to the memory.

  107.    1: Transfer from the memory to the peripheral.*/



  108.   //------设置模式------  

  109.   DMA1_C1CR_CIRC=1;

  110. /* Auto-reload mode

  111.    0: Circular mode disabled.

  112.    1: Circular mode enabled.   */


  113.   //------设置增还是减地址------   

  114.   DMA1_C1CR_MINCDEC=1;

  115. /*  0: Decrement mode.

  116.     1: Increment mode.*/


  117.   //------设置传送数据位数------

  118.   DMA1_C1SPR_TSIZE=1;

  119. /*  0: 8-bit mode

  120.     1: 16-bit mode */

  121.   

  122.   // DMA1_C3CR_HTIE=1;

  123.     DMA1_C1CR_TCIE=1;//使能DMA传输完一组数据中断

  124.    

  125.     //------设置DMA通道1外设地址------

  126.   DMA1_C1PARH=(uint8_t)((uint16_t)ADC_DRH_ADRESS >> (uint8_t)8);

  127.   DMA1_C1PARL=(uint8_t)ADC_DRH_ADRESS;

  128.    

  129.   //------设置DMA通道1内存地址------

  130.   DMA1_C1M0ARH=(uint8_t)((uint16_t)&ui16RX_buffer >> (uint8_t)8);

  131.   DMA1_C1M0ARL=(uint8_t)&ui16RX_buffer;

  132.   


  133.   

  134.   DMA1_C1CR_EN=1;

  135.   

  136.   DMA1_GCSR_GEN=1;

  137. }

  138. void main(void)

  139. {

  140.   GPIO_Config();

  141.   ADC_Init();

  142.   DMA_Config();

  143.   asm("rim");               //enable interrupts

  144.   while(1)

  145.   {

  146.     delay_100ms();

  147.     ADC1_CR1_START=1;

  148.   }

  149. }

  150. /******************************************************************************************************

  151. * 名    称: DMA中断

  152. * 功    能: DMA事件处理函数

  153. * 入口参数:无

  154. * 出口参数:无

  155. * 说   明:

  156. * 范   例:无

  157. ******************************************************************************************************/

  158. #pragma vector=DMA1_CH1_TC_vector

  159. __interrupt void DMA1_CH1_TC_ISR(void)

  160. {

  161.    static uint16_t tmp=0,voltage=0;//static是为了便于使用调试窗口查看变量值

  162.    uint8_t i=0;

  163.    tmp=0;

  164.    voltage=0;

  165.    if(DMA1_C1SPR_TCIF==1)

  166.    {

  167.      PC_ODR_ODR7 ^=0x01;//反转蓝灯电平,仅仅是为了指示ADC和DMA在工作,可去掉

  168.      DMA1_C1SPR_TCIF=0;//不软件清除此中断标志位,会导致无法退出此中断

  169.      for(i=0;i<9;i++)tmp+=ui16RX_buffer[i];

  170.      tmp /=9;//求九次采样平均值     

  171.      voltage=(uint32_t)299*tmp/4096;//计算最终输出的电压,结果扩大了100倍

  172.      //299是2.99V参考电压,扩大了100倍

  173.      asm("nop");

  174.    }

  175. }

  176. /******************************************************************************************************

  177. * 名               称: ADC中断

  178. * 功         能: EOC事件处理函数

  179. * 入口           参数:无

  180. * 出口           参数:无

  181. * 说               明:

  182. * 范              例:无

  183. ******************************************************************************************************/

  184. //#pragma vector=COMP_EF2_vector

  185. //__interrupt void ADC1_ISR(void)

  186. //{

  187. //   static uint16_t tmp=0;

  188. //   if(ADC1_SR_EOC==1)

  189. //   {

  190. //     PC_ODR_ODR7 ^=0x01;

  191. //     ADC1_SR_EOC=0;

  192. //     tmp = ADC1_DRH;

  193. //     tmp = (tmp<<8)+ADC1_DRL;

  194. //     tmp=(uint32_t)299*tmp/4096;

  195. ////     VDD_Value=(uint32_t)1225*4096/temp;//得到的数值单位为mv

  196. //     asm("nop");

  197. //   }

  198. //}
复制代码
回复

使用道具 举报

ID:281905 发表于 2018-2-3 11:35 | 显示全部楼层
请教一个问题:我用的STM8L151K4 查看配置资料和STM8L152C6大概一致,我用AIN0测热敏电子电压,发现DMA1_CH1_TC_vector中断始终进不来,而你的另一份文档测内部VDD电压运行正常,请教问题可能是哪里。我用的是IAR for STM8,中断向量表已经对过,没问题
回复

使用道具 举报

ID:281905 发表于 2018-2-3 11:37 | 显示全部楼层
请教STM8L151K4 使用DMA ,按照你的文档COPY的,进不了中断
回复

使用道具 举报

ID:281905 发表于 2018-2-6 14:56 | 显示全部楼层
谢谢!测量次数不够没进中断,非常感谢分享
回复

使用道具 举报

ID:18591 发表于 2019-3-2 14:28 | 显示全部楼层
按照你的文檔COPY的,进不了中断
你说,测量次数不够没进中断,不懂你的意思
可以说清处一点?
回复

使用道具 举报

ID:646563 发表于 2019-11-21 15:34 | 显示全部楼层
你好!请问我copy你这个程序在IAR上为什么进入不了中断?谢谢
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表