标题:
STM8L的ADC之测量外部电压(使用了DMA)
[打印本页]
作者:
51hei小林
时间:
2016-10-9 23:58
标题:
STM8L的ADC之测量外部电压(使用了DMA)
本帖最后由 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");
// }
//}
复制代码
作者:
hy345612553
时间:
2018-2-3 11:35
请教一个问题:我用的STM8L151K4 查看配置资料和STM8L152C6大概一致,我用AIN0测热敏电子电压,发现DMA1_CH1_TC_vector中断始终进不来,而你的另一份文档测内部VDD电压运行正常,请教问题可能是哪里。我用的是IAR for STM8,中断向量表已经对过,没问题
作者:
hy345612553
时间:
2018-2-3 11:37
请教STM8L151K4 使用DMA ,按照你的文档COPY的,进不了中断
作者:
hy345612553
时间:
2018-2-6 14:56
谢谢!测量次数不够没进中断,非常感谢分享
作者:
jxchen
时间:
2019-3-2 14:28
按照你的文檔COPY的,进不了中断
你说,测量次数不够没进中断,不懂你的意思
可以说清处一点?
作者:
zhuizhuizhui135
时间:
2019-11-21 15:34
你好!请问我copy你这个程序在IAR上为什么进入不了中断?谢谢
欢迎光临 (http://www.51hei.com/bbs/)
Powered by Discuz! X3.1