本帖最后由 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.

- /*硬件连接*/
- // PD5(ADC1_IN9) <----
- /****************************************************************************************
- *开发环境:IAR for stm8 v1.40.1
- *硬件平台:STM8L-DISCOVERY
- *功能说明:测量ADC通道9的外部电压,通道9对应的引脚为PD5,在此引脚接了一个电位器,用于输出一个
- * 可变的电压,提供给ADC测量
- *作 者:茗风
- ****************************************************************************************/
- #include"iostm8l152c6.h"
- #include"stdbool.h"
- #include"stdint.h"
- #define ADC_DRH_ADRESS 0x5344
- uint16_t ui16RX_buffer[9]={0};
- /******************************************************************************************************
- * 名 称:void delay_10ms(uint8_t x_ms)
- * 功 能:延时10ms
- * 入口参数:无
- * 出口参数:无
- * 说 明:
- * 范 例:无
- ******************************************************************************************************/
- void delay_100ms(void)
- {
- uint8_t i,j;
- for(i=0;i<255;i++)//2*255个指令周期
- for(j=0;j<255;j++);//2*255个指令周期
- //delay_10ms共消耗 x_ms*2*255+2*x_ms个指令周期
- //255*2*255+2*255=130610us=130ms
- //此延时函数,延时时间为130ms
- //16M/8/2=1M 一个指令周期为1us
- }
- /******************************************************************************************************
- * 名 称:void GPIO_Init(void)
- * 功 能:初始化PC7为高速推挽输出
- * 入口参数:无
- * 出口参数:无
- * 说 明:
- * 范 例:无
- ******************************************************************************************************/
- void GPIO_Config(void)
- {
- PC_CR1_C17 =1;//推挽输出
- PC_CR2_C27 =1;//高速输出
- PC_DDR_DDR7 =1;//PC7输出
- PC_ODR_ODR7 =0;//输出低电平
- }
- /******************************************************************************************************
- * 名 称:void ADC_Init(void)
- * 功 能:初始化ADC
- * 入口参数:无
- * 出口参数:无
- * 说 明:ADC1的测量通道为ADC1_IN9,单次转换模式
- * 范 例:无
- ******************************************************************************************************/
- void ADC_Init(void)
- {
- CLK_PCKENR2_PCKEN20=1; //国际惯例,开启ADC1外设时钟
- ADC1_CR1_ADON=1; //wakes up the ADC from Power down mode.
- ADC1_CR2_PRESC=1;//Select a sample time of 10 μs
- // 0: f(ADC_CLK) = CK
- // 1: f(ADC_CLK) = CK/2 //系统时钟此时为默认的16M/8=2M,这里分频后,fadc=2M/2=1M
-
- ADC1_SQR1_DMAOFF=0; //使能DMA
-
- ADC1_CR3_SMTP2=0x06;//采样时间为24 ADC clock cycles,也就是24*1us=24us
- //000: 4 ADC clock cycles
- //001: 9 ADC clock cycles
- //010: 16 ADC clock cycles
- //011: 24 ADC clock cycles
- //100: 48 ADC clock cycles
- //101: 96 ADC clock cycles
- //110: 192 ADC clock cycles
- //111: 384 ADC clock cycles
- ADC1_SQR3_CHSEL_S9=1; //选择通道9
- ADC1_TRIGR3_TRIG9=1; //关闭通道9的施密特触发器
- // ADC1_CR1_EOCIE=1;
- }
- /******************************************************************************************************
- * 名 称:void DMA_Config(void)
- * 功 能:启用DMA
- * 入口参数:无
- * 出口参数:无
- * 说 明:
- * 范 例:无
- ******************************************************************************************************/
- void DMA_Config(void)
- {
- //------打开DAM时钟------
- CLK_PCKENR2_PCKEN24=1;
-
- //----设置ADC的DMA通道----
- SYSCFG_RMPCR1_ADC1DMA_REMAP=1;
- /* 00: ADC1 DMA request/acknowledge mapped on DMA1 channel 0
- 01: ADC1 DMA request/acknowledge mapped on DMA1 channel 1
- 10: ADC1 DMA request/acknowledge mapped on DMA1 channel 2
- 11: ADC1 DMA request/acknowledge mapped on DMA1 channel 3 */
-
- //------设置传送的字节数,------
- DMA1_C1NDTR=9;
-
- //------设置通道优先级------
- DMA1_C1SPR_PL0=0;DMA1_C1SPR_PL1=1;
- //------设置传送方向------
- DMA1_C1CR_DIR=0;
- /* 0: Transfer from the peripheral to the memory.
- 1: Transfer from the memory to the peripheral.*/
- //------设置模式------
- DMA1_C1CR_CIRC=1;
- /* Auto-reload mode
- 0: Circular mode disabled.
- 1: Circular mode enabled. */
- //------设置增还是减地址------
- DMA1_C1CR_MINCDEC=1;
- /* 0: Decrement mode.
- 1: Increment mode.*/
- //------设置传送数据位数------
- DMA1_C1SPR_TSIZE=1;
- /* 0: 8-bit mode
- 1: 16-bit mode */
-
- // DMA1_C3CR_HTIE=1;
- DMA1_C1CR_TCIE=1;//使能DMA传输完一组数据中断
-
- //------设置DMA通道1外设地址------
- DMA1_C1PARH=(uint8_t)((uint16_t)ADC_DRH_ADRESS >> (uint8_t)8);
- DMA1_C1PARL=(uint8_t)ADC_DRH_ADRESS;
-
- //------设置DMA通道1内存地址------
- DMA1_C1M0ARH=(uint8_t)((uint16_t)&ui16RX_buffer >> (uint8_t)8);
- DMA1_C1M0ARL=(uint8_t)&ui16RX_buffer;
-
-
- DMA1_C1CR_EN=1;
-
- DMA1_GCSR_GEN=1;
- }
- void main(void)
- {
- GPIO_Config();
- ADC_Init();
- DMA_Config();
- asm("rim"); //enable interrupts
- while(1)
- {
- delay_100ms();
- ADC1_CR1_START=1;
- }
- }
- /******************************************************************************************************
- * 名 称: DMA中断
- * 功 能: DMA事件处理函数
- * 入口参数:无
- * 出口参数:无
- * 说 明:
- * 范 例:无
- ******************************************************************************************************/
- #pragma vector=DMA1_CH1_TC_vector
- __interrupt void DMA1_CH1_TC_ISR(void)
- {
- static uint16_t tmp=0,voltage=0;//static是为了便于使用调试窗口查看变量值
- uint8_t i=0;
- tmp=0;
- voltage=0;
- if(DMA1_C1SPR_TCIF==1)
- {
- PC_ODR_ODR7 ^=0x01;//反转蓝灯电平,仅仅是为了指示ADC和DMA在工作,可去掉
- DMA1_C1SPR_TCIF=0;//不软件清除此中断标志位,会导致无法退出此中断
- for(i=0;i<9;i++)tmp+=ui16RX_buffer[i];
- tmp /=9;//求九次采样平均值
- voltage=(uint32_t)299*tmp/4096;//计算最终输出的电压,结果扩大了100倍
- //299是2.99V参考电压,扩大了100倍
- asm("nop");
- }
- }
- /******************************************************************************************************
- * 名 称: ADC中断
- * 功 能: EOC事件处理函数
- * 入口 参数:无
- * 出口 参数:无
- * 说 明:
- * 范 例:无
- ******************************************************************************************************/
- //#pragma vector=COMP_EF2_vector
- //__interrupt void ADC1_ISR(void)
- //{
- // static uint16_t tmp=0;
- // if(ADC1_SR_EOC==1)
- // {
- // PC_ODR_ODR7 ^=0x01;
- // ADC1_SR_EOC=0;
- // tmp = ADC1_DRH;
- // tmp = (tmp<<8)+ADC1_DRL;
- // tmp=(uint32_t)299*tmp/4096;
- //// VDD_Value=(uint32_t)1225*4096/temp;//得到的数值单位为mv
- // asm("nop");
- // }
- //}
复制代码 |