历史上的今天
返回首页

历史上的今天

今天是:2024年10月24日(星期四)

正在发生

2019年10月24日 | stm32 ADC全解(单次,连续DMA传输)

2019-10-24 来源:eefocus

学习STM32的ADC转换,在开发板上写程序调试。

四个任务:

四个任务:

1.AD以中断方式(单次)采集一路

2.AD以中断方式连续采集四路

3.ADC多路采集,DMA传输,DMA深度为一级

4.ADC以DMA方式采集四路,每路DMA深度为28级,并滤波,说明滤波原理


总结:

第一个任务

:ADC以中断方式采集一路ADC,通过配置ADC_InitStructure结构体中的ADC_ScanConvMode,它规定模数转换工作在扫描模式(多通道)还是单次模式(单通道),

ADC_InitStructure.ADC_ScanConvMode=DISABLE,为单通道单次模式。

ADC_ContinuousConvMode,定转换是连续还是单次,ADC_ContinuousConvMode=DISABLE

为单次,ADC_NbrOfChangnel规定ADC规则转换的通道数。ADC_NbrOfChannel=1;//开启1个通道数。


ADC_RegularChannelConfig(ADC1,ADC_Channel_13, 1,ADC_SampleTime_55Cycles5);设置指定规则组的通道的采样顺序和转换时间。这里以为只有一路通道,采用的是PC3引脚,对应的通道数是13通道,采样顺序也就是1,。

ADC_Cmd(ADC1,ENABLE);使能ADC

ADC_ITConfig(ADC1, ADC_IT_EOC,ENABLE);开启ADC转换结束中断。

ADC_ResetCalibration(ADC1);//重置校验寄存器

while(ADC_GetResetCalibrationStatus(ADC1)); //等待重置校验成功

ADC_StartCalibration(ADC1);//开始ADC校验

while(ADC_GetCalibrationStatus(ADC1));//等待ADC校验好

ADC_SoftwareStartConvCmd(ADC1, ENABLE);//软件触发开始转换

因为ADC有一个16位的规则组数据寄存器(ADC_DR),采用一路转换时可以不用通过DMA传输。这里就没有配置DMA。

void ADC_IRQHandler(void)

{

       ADCConvertedValue=ADC_GetConversionValue(ADC1); 

       ADC_ClearITPendingBit(ADC1, ADC_IT_EOC);            

}

当一次转换结束,DAC产生中断,在中断函数里,读取ADC_DR寄存器中的值,一定清除中断标志位。


采集出来的数据是16进制数,要经过处理,变成10进制数,具体如下:

(value*100/4096)*33,value是从寄存器读出来的十六进制的数据,经过此变换后就变成10进制数,是个整数,我们通过串口显示的时候要把小树部分也要显示出来则有:((value*100/4096)*33)/1000,整数部分。


((value*100/4096)*33)00/100,((value*100/4096)*33)0/10),小数部分,

串口配置,我是通过STM32上的串口1与PC机通讯的,具体配置如下:

void USART_Configuration(void)

{

       USART_InitTypeDef USART_InitStructure;

       USART_InitStructure.USART_BaudRate=9600;波特率9600

     USART_InitStructure.USART_WordLength=USART_WordLength_8b;//8位数据位

     USART_InitStructure.USART_StopBits=USART_StopBits_1;1个停止位

     USART_InitStructure.USART_Parity=USART_Parity_No;无奇偶校验

     USART_InitStructure.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;       USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;

       USART_Init(USART1,&USART_InitStructure);初始化串口配置

       USART_Cmd(USART1,ENABLE);使能串口

}

int fputc(int ch,FILE *f)

{

       USART_SendData(USART1, (u8)ch);

       while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET)//检查发送是否完成

       {

       }

       return ch;

}此函数,是把printf输出函数定向到USART。


第一个任务大概就是这个过程,在后面的任务有相同之处,就不重复叙述了。

第二个任务:ADC以中断方式连续采集四路。


首先配置4路模拟输入,我配置的是PC0、PC1、PC2、PC3四个IO口,输入方式为模拟输入,速度采用2M,它们对应的ADC通道分别是10、11、12、13通道。


在第一个任务说了,ADC规则转换多路采样时,ADC的数据寄存器只有一个16位寄存器,所以必须采用DMA来传输数据,DMA配置如下:

DMA_InitStructure.DMA_PeripheralBaseAddr=DR_ADDRESS; //DMA对应的外设基地址

DMA_InitStructure.DMA_MemoryBaseAddr=(u32)&Buf; //内存存储基地址,定义的一个数组

DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralSRC; //DMA转换模式为SRC模式,由外设搬移到内存

DMA_InitStructure.DMA_BufferSize=4; // DMA缓存大小,4个(设置DMA在传输时缓冲区的长度)

DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable; //接收一次数据后,设备地址禁止后移(设置DMA的外设递增模式)

DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable; //关闭接收一次数据后,目标内存地址后移(设置DMA的内存递增模式)

DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_HalfWord;//定义外设数据长度

DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_HalfWord;

DMA_InitStructure.DMA_Mode=DMA_Mode_Circular;

//循环模式开启,Buf写满后,自动回到初始地址开始传输

DMA_InitStructure.DMA_Priority=DMA_Priority_High;//优先级高

DMA_InitStructure.DMA_M2M=DMA_M2M_Disable;

ADC配置:

//ADC配置

       ADC_InitStructure.ADC_Mode=ADC_Mode_Independent;//独立转换模式

     ADC_InitStructure.ADC_ScanConvMode=ENABLE;//开启扫描模式

     ADC_InitStructure.ADC_ContinuousConvMode=ENABLE;//开启连续转换模式

     ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;//ADC外部开关,关闭状态

     ADC_InitStructure.ADC_DataAlign=ADC_DataAlign_Right;//对齐方式,右对齐方式

     ADC_InitStructure.ADC_NbrOfChannel=4;//开启通道数,4个

       ADC_Init(ADC1,&ADC_InitStructure);//初始化ADC

       ADC_RegularChannelConfig(ADC1,ADC_Channel_10,1,ADC_SampleTime_55Cycles5);

       ADC_RegularChannelConfig(ADC1,ADC_Channel_11,2,ADC_SampleTime_55Cycles5);

       ADC_RegularChannelConfig(ADC1, ADC_Channel_12,3,ADC_SampleTime_55Cycles5);

       ADC_RegularChannelConfig(ADC1,ADC_Channel_13,4,ADC_SampleTime_55Cycles5);;

       //ADC通道组,第10、11、12、13个通道,采样顺序分别是1,2,3,4转换时间55.5个周期

       ADC_DMACmd(ADC1, ENABLE);//使能ADC1模块DMA

       ADC_Cmd(ADC1, ENABLE);//打开ADC1

       ADC_ResetCalibration(ADC1);//重置ADC1校准寄存器

       while(ADC_GetResetCalibrationStatus(ADC1));//等待ADC1校准重置完成

       ADC_StartCalibration(ADC1);//开始ADC1校准

       while(ADC_GetCalibrationStatus(ADC1));//等待ADC1校准完成

       ADC_SoftwareStartConvCmd(ADC1,ENABLE);//使能ADC1软件开始转换

中断是采用DMA中断,当DMA第一轮传输结束时,设一个标志位,当标志位为1时,表明第一轮转化和传输完成,此时就可以读取数组中的数据,经过处理就可以通过串口显示出来。


void DMAChannel1_IRQHandler(void)

{         

              ADC_DMA_OK=1;

              DMA_ClearITPendingBit(DMA1_IT_TC1);              

}中断函数。


第二个任务大概就这样子。

第三个任务:AD以DMA方式采集一路,DMA深度为一级。

这个任务不难,关键要理解到DMA深度,用自己的语言来理解哈DMA深度吧,当ADC以一路采集时,ADC转换完成就自动把转换结果通过DMA传给目的地址,如果传输一次结束DMA就产生中断的话,DMA的深度就为一级,如果连续传输N次,DMA的深度就位N级,当然这个N是又范围的,因为受目的地址的内存大小控制和数据宽度,这个大家应该豆明白的。


这个任务在第一个任务的基础上我通过DMA传输,意思是AD配置没什么区别。DMA配置和第二个任务的区别就是DMA_BufferSize的宽度不同。


#define DR_ADDRESS   (u32)0x4001244c ADC的地址

#define DMA_Count    1   DMA深度,也就是连续传输的次数

#define ADC_Channle 1 ADC通道

数据处理和串口通讯这里不重复叙述。DMA中断和任务二的类似。

第四个任务:AD以DMA方式采集四路,每路DMA深度为128级,并滤波,说明滤波原理。


这个任务和是个综合性任务,只要弄懂前面三个任务,难点是再如何滤波,开始的时候我也不知道怎么滤波,同事提醒我才知道怎么滤波的,我大概说哈我的理解,把四路通道采集的数据分别放到四个数组中,然后给他来个排序,降序,升序都行,把首位两个数丢掉,然后加起来求平均值。但是我这里因为DMA的深度为128级,也就是四个通道分别采样了128次,大家都知道,数据越多,求平均值就越准确,所以我就没有采用什么排序法了,直接给他们分别求平均值,具体如下:


#define DR_ADDRESS   (u32)0x4001244c ADC的地址

#define DMA_Count    128   DMA深度,也就是连续传输的次数

#define ADC_Channle 4 ADC通道

       for(i=0;i<(ADC_Channle*DMA_Count);i+=4)

                     {                  

                            Value1[j]=Buf[i+0];

                            Sum1+=Value1[j];                      

                            Value2[j]=Buf[i+1];

                            Sum2+=Value2[j];                      

                            Value3[j]=Buf[i+2];

                            Sum3+=Value3[j];

                            Value4[j]=Buf[i+3];

                            Sum4+=Value4[j];

                            j++;

                     }           

              Valu1=Sum1/DMA_Count;

              Valu2=Sum2/DMA_Count;

              Valu3=Sum3/DMA_Count;

              Valu4=Sum4/DMA_Count;

              Delay(100000);     

              printf("rn当前AD_0值:0x%x,电压值:%d.%d%dVnr",

              Valu1,((Valu1*100/4096)*33)/1000,((Valu1*100/4096)*33)00/100,((Valu1*100/4096)*33)0/10);

推荐阅读

史海拾趣

ECLIPSE公司的发展小趣事

2001年,IBM公司决定推动一个开源项目,旨在打造一个全新的集成开发环境。这个项目名为Eclipse,旨在通过开放源代码的方式,吸引全球开发者共同参与。Eclipse的初始版本发布后,凭借其优秀的性能和友好的界面,迅速在开发者社区中引起了关注。

Filtran Ltd公司的发展小趣事

随着业务规模的扩大,Filtran Ltd意识到供应链管理的重要性。公司开始在全球范围内寻找优质原材料供应商,并在亚洲和欧洲建立了生产基地,以降低成本并缩短交货周期。同时,通过引入先进的ERP系统和数字化管理工具,实现了供应链的高效协同。这一战略调整不仅提高了生产效率,还增强了公司对市场变化的快速响应能力。

硕颉(BITEK)公司的发展小趣事

硕颉科技股份有限公司成立于1999年11月,总部设在台北市。自成立以来,公司一直专注于积体电路的设计、研发与销售,致力于为客户提供高质量的电子产品解决方案。在创立初期,硕颉便以其创新的技术和严谨的研发态度,迅速在电子行业崭露头角。公司资本额为新台币三亿三仟万元,为公司的稳健发展提供了坚实的资金基础。

台湾富致(FUZETEC)公司的发展小趣事

除了在工业控制和汽车领域取得显著成就外,Futaba还将其技术延伸至休闲娱乐领域。公司开发的遥控飞机、车、船等产品,凭借其先进的无线遥控技术和卓越的性能表现,成为户外休闲运动的热门选择。特别是2.4G接收机的推出,进一步丰富了Futaba的产品线,满足了不同消费者的需求。在航模遥控器市场中,Futaba凭借其独特的技术优势和品牌影响力,占据了重要地位。这一领域的拓展不仅为公司带来了新的增长点,还进一步提升了Futaba在全球电子行业中的知名度和影响力。

北京人民电器厂公司的发展小趣事

为了提高生产效率和产品质量,北京人民电器投入大量资金建设了自动化装配检测流水线。这一举措使得公司的生产能力得到了大幅提升,同时也确保了产品的一致性和可靠性。自动化流水线的建设,是北京人民电器在现代化生产道路上迈出的重要一步。

永源微电子(APM)公司的发展小趣事

2023年,永源微电子成功完成了A轮融资,这是公司发展过程中的一个重要里程碑。此次融资由深圳英集芯科技股份有限公司领投,为公司带来了丰富的资金支持和市场资源。通过与英集芯科技的战略合作,永源微电子在微电子领域的技术创新和产品研发上取得了新的突破。双方共同开展研发项目,推动技术的突破和应用场景的拓展,为公司的未来发展注入了强大的动力。

问答坊 | AI 解惑

标准化将推进汽车总线技术应用深入

  随着电子与信息技术在汽车中的渗透,汽车中内嵌CPU的智能化零部件在不断增加,在智能零部件之间充当信息交互桥梁的总线,包括CAN、CIN、FlexRey、MOST、IDB1394等已成为现代汽车的关键技术。  应用层标准化是促进总线技术应用的重要措施   ...…

查看全部问答>

单片机知识

单片机是指一个集成在一块芯片上的完整计算机系统。尽管他的大部分功能集成在一块小芯片上,但是它具有一个完整计算机所需要的大部分部件:CPU、内存、内部和外部总线系统,目前大部分还会具有外存。同时集成诸如通讯接口、定时器,实时时钟等外围 ...…

查看全部问答>

笔记本电脑视频采集卡问题

大家帮帮忙,我原来在台式机上有一个软件是采集显微镜图片的,用的是天敏sdk2000的采集卡,现在我把软件装在笔记本上面了,用什么办法可以用,笔记本用的采集卡继续使用这个软件,怎么设置,请高手指教,…

查看全部问答>

有关AD的一个小问题(新手)

有关LM3S系列的AD,在看资料和例程的时候,发现转换结果都是在一个序列采集完成后,再一起读出,那在AD采集的时候,结果都放在哪里了呢?如果设置一个8通道的序列,那是不是得需要80bit的缓存?小弟新人,求哪位大侠指点,谢谢!…

查看全部问答>

低功耗问题

我用的是 msp149 LFXT1=32K; XT2=7.3728M; 我想让MCLK=32K main(){ WDTCTL = WDTPW + WDTHOLD; BCSCTL1&=~XTS; //选择LFXT1低频 _BIC_SR(OSCOFF);//启动lfxt ... ... BCSCTL2=SELM1+SELM0; //set MCLK same as LFXT1CLK ...…

查看全部问答>

STM32W 抓包软件

可以用到的转包软件…

查看全部问答>

PROTEL99SE

PROTEL99SE打印元件的位置图时会显示没有孔装载,怎么解释我用的是汉化的 用英文的又不知道怎么打印元件位置图…

查看全部问答>

FPGA的选择

有谁可以推荐一个ALTER的160的I/O的性能稳定的芯片啊…

查看全部问答>

推荐款STM32F的型号

功能要求:     1、8路AD同时采样     2、6路pwm输出,带死区控制     3、指令周期40M以上…

查看全部问答>