1
完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
1个回答
|
|
编者按: 在学ADC的途中遇到了几个自我感觉比较难以理解的点,在这里做一个记录。学习参考资料: 正点原子:STM32F1开发指南、STM32F1中文参考手册 Z小璇博客:【STM32】HAL库 STM32CubeMX教程九—ADC 1. ADC的转换模式 1。单次转换模式:ADC只执行一次转换; 2。连续转换模式:转换结束之后马上开始新的转换; Stm323。 扫描模式:ADC扫描被规则通道和注入通道选中的所有通道,在每个组的每个通道上执行单次转换。在每个转换结束时,这一组的下一个通道被自动转换。如果设置了CONT位(开启了连续 转换模式),转换不会在选择组的最后一个通道上停止,而是再次从选择组的第一个通道继续转换。 4。间断模式:触发一次,转换一个通道,在触发,在转换。在所选转换通道循环,由触发信号启动新一轮的转换,直到转换完成为止。 扫描模式简单的说是一次对所有所选中的通道进行转换,比如开了ch0,ch1,ch4,ch5。 ch0转换完以后就会自动转换通道1,4,5直到转换完这个过程不能被打断。如果开启了连续转换模式,则会在转换完ch5之后开始新一轮的转换。 这就引入了间断模式,可以说是对扫描模式的一种补充。它可以把0,1,4,5这四个通道进行分组。可以分成0,1一组,4,5一组。也可以每个通道单独配置为一组。这样每一组转换之前都需要先触发一次。 ADC单通道: 只进行一次ADC转换:配置为“单次转换模式”,扫描模式关闭。ADC通道转换一次后,就停止转换。等待再次使能后才会重新转换 进行连续ADC转换:配置为“连续转换模式”,扫描模式关闭。ADC通道转换一次后,接着进行下一次转换,不断连续。 ADC多通道: 只进行一次ADC转换:配置为“单次转换模式”,扫描模式使能。ADC的多个通道,按照配置的顺序依次转换一次后,就停止转换。等待再次使能后才会重新转换 进行连续ADC转换:配置为“连续转换模式”,扫描模式使能。ADC的多个通道,按照配置的顺序依次转换一次后,接着进行下一次转换,不断连续。 也就是:多通道必须使能扫描模式 Stm32 ADC的单次模式和连续模式。这两中模式的概念是相对应的。这里的单次模式并不是指一个通道。假如你同时开了ch0,ch1,ch4,ch5这四个通道。单次模式转换模式下会把这四个通道采集一边就停止了。而连续模式就是这四个通道转换完以后再循环过来再从ch0开始。 2. 多通道的配置(无DMA) 以下部分参考文章:Stm32cubeMx配置ADC多通道采集 “目前经过我的测试,要想用非dma和中断模式只有这样配置可以正确进行多通道转换:扫描模式+单次转换模式+间断转换模式(每个间断组一个通道)。 分析配置成这样的模式,扫描模式是在配置为多个通道必须打开的,stm32cubeMX上也默认好了,只能enable。单次转换模式是我不需要不停的去采集每个通道值,而是把四个通道采集完以后就让它停止。这里间断配置是关键,间断模式可以让扫描的四个通道进行分成四个组,stm32cubeMX参数里面number of Discontinous Conversions是配置间断组每个组有几个通道的,这里必须配置为1(否则在获取ad值得时候只能读取到每个间断组最后一个通道)。” 参照上文配置如下: 代码如下: while (1) { for(i=0;i<2;i++){ HAL_ADC_Start(&hadc1); //开启ADC转换 HAL_ADC_PollForConversion(&hadc1, 50); //等待转换结束 if(HAL_IS_BIT_SET(HAL_ADC_GetState(&hadc1), HAL_ADC_STATE_REG_EOC)) { ADC_Value = HAL_ADC_GetValue(&hadc1); printf("PA%d Reading : %d rn",i,ADC_Value); } } printf("hello ADCrn"); HAL_Delay(1000); } 用自己的话总结一下,像下面这张图,假设开启的是3个通道,都放在规则组里面,那扫描+单次模式就是按黑色的从start到end的直线执行,此时利用HAL_ADC_GetValue(&hadc1)去获取转化后的数据,无法确定这个数据是哪一个通道的(最有可能是最后一个通道的,因为按照顺序转换,后面的数据会覆盖前面的)。间断模式就是蓝线的部分,它给整个流程加上了暂停键,在每转换一个通道后就暂停一次,在暂停期间去读数据,就能够确保这个数据就是这个通道的。 “在STM32的手册中,我们发现,不论是单次采集还是多次采集,转换完成的数据都会放在同一个地方。 由于DR寄存器不是一个数组,而是一个字节,所以只能保存最新的转换结果。例如,通道1和通道2都使用,通道1的转换结果放在DR寄存器。通道2转换完毕以后,就会覆盖通道1的结果。 程序里,当然可以通过一些处理,让通道1的结果在被覆盖之前就保存好。不过,运用STM32的DMA功能,可以更好地解决结果被覆盖的问题。” 3. 多通道的配置(DMA) 此部分参考: HAL库教程12:ADC与DMA采集多路AD值 基于DMA的ADC多通道采集_亲测 STM32F的利用HAL库ADC转换DMA方式多通道采样调试总结 “DMA和外设之间大致的工作流程,就拿ADC来说,当启动了ADC_DMACmd()(这个是ADC的配置寄存器可以自己查看数据手册)这个函数后,DMA和ADC之间就建立了链接。在发生一个事件后,外设向DMA控制器发送一个请求信号。DMA控制器根据通道的优先权处理请求。当DMA控制器开始访问发出请求的外设时,DMA控制器立即发送给它一个应答信号。当从DMA控制器得到应答信号时,外设立即释放它的请求。一旦外设释放了这个请求,DMA控制器同时撤销应答信号。如果有更多的请求时,外设可以启动下一个周期。” “ 循环模式用于处理循环缓冲区和连续的数据传输(如ADC的扫描模式)。在DMA_CCRx寄存器中的CIRC位用于开启这一功能。当启动了循环模式,数据传输的数目变为0时,将会自动地被恢复成配置通道时设置的初值,DMA操作将会继续进行。说一下这个循环缓冲区,DMA占用的也是内核的系统数据总线,而这个总线想必大家都知道那可不是在总线上待着玩呢,都是瞬时完成的。每当ADC转化一次数据完成之后(也就是CPU处理了数据你可以理解为你的电压值),DMA说,大哥你只管计算数据就啦,剩下的交给我吧,即DMA占用一下数据总线(查的手册为占用一半的资源),把数据发送到你定义的二维数组地址下的存储空间。假设你定义了10组两个通道大小的AD值,那么ADC会一直转换直到20组,那么在这个过程当中,CPU只管计算(比如采样、编码、量化等,这些可查看ADC)之后DMA尽快的去把数据送到二维数组当中。在这个DMA送数据的连续过程当中就为循环缓冲区。" 大概捋一捋自己的理解: ADC开启DMA功能,正如上文所说,就是将ADC和DMA链接了起来,当转换完一个数据的时候,就立马向DMA发送请求,DMA响应之后立马把DR寄存器中的数据移走放在内存的一个数组中,如此一来转换的数据就不会被覆盖,也不用开启间断模式停止扫描移走数据。 HAL_ADC_Start_DMA(&hadc1, (uint32_t*) DMA_BUF, 2); while (1) { printf("count = %drn",count); printf("hello ADCrn"); printf("DMA0 = %drn",DMA_BUF[0]); printf("DMA1 = %drn",DMA_BUF[1]); if(HAL_DMA_GetState(&hdma_adc1) != HAL_DMA_STATE_BUSY) { printf("DMA0 = %drn",DMA_BUF[0]); printf("DMA1 = %drn",DMA_BUF[1]); printf("count = %drn",count); } HAL_Delay(1000); } 在main.c中添加主函数如上。 在此DMA开启的是循环模式,就是说每一次传输完2个数据之后,又重新开始传输这两个数据。在此模式下,ADC必须是扫描连续模式,才能一直有数据被传送。 有意思的是,在代码中if(HAL_DMA_GetState(&hdma_adc1) != HAL_DMA_STATE_BUSY)这个条件永远是不成立的,大概是因为循环模式下DMA是不会自己停止的吧。 【2020.7.22】补充 HAL_ADC_Start_DMA(&hadc1, (uint32_t*) DMA_BUF, 2); while (1) { // printf("count = %drn",count); // printf("hello ADCrn"); printf("DMA0 = %drn",DMA_BUF[0]); printf("DMA1 = %drn",DMA_BUF[1]); arr[0] = arr[0]+DMA_BUF[0]; arr[1] = arr[1]+DMA_BUF[0]; i++; if(i%10 == 0) { printf("rnarr0 = %drn",arr[0]/10); printf("arr1 = %drn",arr[1]/10); printf("count = %drn",count); printf("i = %drnrn",i); arr[0] = 0; arr[1] = 0; } HAL_Delay(1000); } 我看到的现象是,DMA_CNT大约是15W,每次两个数据,也就是DMA1秒钟搬运了30W个字节。可以想象,如果不是AD转换速度限制,DMA还可以更快一点.” 又花了一些时间(fine,不止一些),再捋一下自己的理解。 DMA的最大好处就是解放了CPU,自主利用数据总线进行数据传输。就是说, HAL_ADC_Start_DMA(&hadc1, (uint32_t*) DMA_BUF, 2); 这个语句之后,不论CPU是在做什么,DMA都在勤勤恳恳地将ADC数据寄存器中的数据搬运到DMA_BUF数组里面,每次DMA循环都会重新覆盖,就是说IN0通道的数据永远放在DMA_BUF[0]。用printf函数打印出来的DMA_BUF[0]就是刚好那个时刻的数据而已。 另外还要注意的点: “1,规则模式下,用户内存缓冲区的数据宽度需要和DMA设置的数据宽度一致。 2 ,多通道顺序参数rank,在配置rank时,如果配置的rank在开启的通道中不连续,DMA无法将转换的数据传到对应的缓冲区,也就和无法读取到该通道的数据。” 3,HAL_ADC_Start_DMA(ADC_HandleTypeDef* hadc, uint32_t* pData, uint32_t Length) 中参数Length为多通道的通道数。 【2020.7.23】补充 此部分参考: [已解决] HAL库 配置DMA_ADC工作后主循环里的函数不工作,求指导 stm32cubemx教程之ADC采集通过DMA传输,听说能省很多CPU时间做其他事 这个问题说来有意思,在开启HAL_ADC_Start_DMA之后,不论主循环的打印都无法显示出来。不知道程序是卡在了HAL_ADC_Start_DMA函数里面还是怎么样,无法,很迷。 查了挺久的资料,看到以上两篇文章,稍稍有点拨开迷雾的意思。 弄清这个问题还挺难,还得从HAL_ADC_Start_DMA这个函数做了什么事情说起。 图片来源:STM32Cube 重点在于DMA传输完成后会自动调用DMA中断函数,也就是为什么一旦配置了DAM模式,MX就一定会开启DMA中断的原因。 上图中可以看到,“DMA传输完成后自动调用名字为ADC_DMAConvCplt()的函数”,是如何看出来的?调用的不是DMA中断函数吗?那就去看看DMA中断函数好了。 一步一步,找到了DMA传输完成的回调函数,可是这个函数看起来很不正常,甚至看不明白…… 其实是这样的(此部分得以理解需得感谢豌豆。) 问:为什么DMA传输完成的回调函数与ADC转换完成的回调函数都是HAL_ADC_ConvCpltCallback,可是在DMA中断函数那里却找不到?且ADC转换完成后对DMA发起的请求,在代码中哪里有体现?首先,两者的回调函数确实是同一个。 其次,DMA中断函数里的回调函数是一个函数指针,它指向的是“返回值为空且参数为一个结构体”的函数(定义如下)。因此我们的问题就变为了找到该指针指向的函数。 void (* XferCpltCallback)( struct __DMA_HandleTypeDef * hdma); /*!< DMA transfer complete callback*/ 在下面的附中,博主指出该函数指针的指向是在下列的开启ADC的函数HAL_ADC_Start_DMA中有表明。 /* Set the DMA transfer complete callback */hadc->DMA_Handle->XferCpltCallback = ADC_DMAConvCplt; 但是两者进入中断的规则有所不同,ADC是在“组”完成转换后进入中断,DMA是在"每个通道"完成ADC后向DMA发起请求、DMA完成该通道数据的传输后进入中断。 最后,ADC转换完成后对DMA发起的请求是在每个通道转换完成都发一次,但是在STM32Cube生成的函数中找不到。 也就是说,在HAL_ADC_Start_DMA这个函数里面,HAL_ADC_ConvCpltCallback告诉了DMA中断回调函数说,嘿!你就是我哦,你要调用的函数就是我哦! 下面就更有意思了。明明说DMA是解放了CPU,但是DMA请求和响应以及DMA的中断都要用到CPU,DMA传输数据的速度极快,就是进入中断十分频繁,所以会出现CPU一直在处理DMA中断而回不到主函数的情况,也就是本次问题所在。 解决方案:
|
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1820 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1634 浏览 1 评论
1104 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
740 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1692 浏览 2 评论
1951浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
756浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
587浏览 3评论
605浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
569浏览 3评论
小黑屋| 手机版| Archiver| 德赢Vwin官网 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-31 00:22 , Processed in 0.814589 second(s), Total 78, Slave 62 queries .
Powered by 德赢Vwin官网 网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
德赢Vwin官网 观察
版权所有 © 湖南华秋数字科技有限公司
德赢Vwin官网 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号