完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
1个回答
|
|
最近两天整天朦朦胧胧的,也不知道做了些什么,时间真的是在不自觉中就溜走了,只是早上起来一个贪玩的念头,一天就会没了,甚至只是晚上一个想看一部电影的念头,就会导致第二天一整天没精神做事。自制力是一个人最重要的品质之一,一个念头的影响是很大的。昨天在CSDN上看到July大牛的一句话:"一个有毅力有内心驱动力的人,一旦认定该做什么事之后,便会不顾规则,且义无反顾,不顾一切的去干。" - 引以为戒。
下面说说我在使用DMA模块对编码器测速的经验吧: 第一件要注意的事情是在安装编码器的时候一定要按照该图,在信号线接上上拉电阻。 编码器的引脚图和上拉电阻的连接方式如图: 对于不接上拉电阻的后果,我表示经历过了。下面给出同样正确的程序,在两种情况下,K60采集并发回的数据: 上拉电阻对编码器信号造成什么影响? 不加上拉电阻时,编码器的信号线输出是小尖波,而加上上拉电阻后,编码器的信号输出为方波。前者K60无法检测脉冲,更不谈测速度一说了。 第二件事就是测速的编程,要变成首先要明白测速的方法要用到哪个模块。测速的方法有很多种,如:在PIT定时中读取LPTM脉冲计数(缺点是无法测两路编码器)、FTM正交解码、DMA测速等。 LPTM的缺点是有两个引脚,但是同时只有一路能使用,因此无法测两路编码器。如图: 我使用的是DMA测速,DMA的优点不言而喻。做过摄像头车的人绝对知道DMA的重要性。在智能车竞赛中,DMA可以采集图像,也可以用测速。 关于DMA测速: 众所周知,DMA在智能车竞赛中的运用是极其广泛和实用的,学会并合理的利用DMA,无疑在比赛中会是一个助力。 简单地说,DMA是直接内存读取(Direct Memory Access),是计算机科学中的一种内存访问技术,DMA模块可以不占用CPU资源传输数据,可以大大提高程序运行速度,从而在智能车竞赛中提高车子对赛道的反应能力。DMA的运用不仅仅局限于智能车竞赛,在很多地方都是有益无害的。 为什么DMA能够不需要CPU的介入传输数据? 在STM32中,DMA单元和Cortex CPU之间对总线使用一种交叉存取的机制,DMA传输遵循相应的传输流程。其中,在数据从内存传输到内存的情况下,每传输一个字要消耗5个时钟周期:1个读周期,1个写周期,插入3个空闲周期归CPU使用。所以,每个DMA通道都只是在总线存取周期才会占用总线,即使传输大量的数据,DMA单元最大也只会在消耗40%的数据总线带宽。 所以说STM32中的DMA与CPU对总线的使用方式是交叉式的。 在K60中,DMA是通过DMA控制器接管数据和地址总线。如果CPU正在执行命令,DMA控制利用空闲的地址和数据总线完成数据传送,某种程度上说,CPU运算和数据传送是在并行进行的。K60的DMA数据的传送分为主循环和副循环。主循环一次可能需要副循环很多次。每个副循环传送完毕,对应的DMA通道就进入空闲模式,等待下一次DMA请求。当所有的DMA传送完毕,即置为DONE标志,并且可以通过设置选择传送完毕是否触发中断。此外,可以通过相关寄存器的设置,使用Kinectis的DMA模块的主副循环链接功能、散聚模式、副循环映射。对DMA模块的相应的寄存器进行初始化后,即可开启DMA功能。 接下来附上使用DMA测速的程序: 第一个是对DMA的初始化函数,如下: void DMACNT_Init(DMACNT_InitTypeDef* DMACNT_InitStruct) { uint8_t Dummy = 0; DMA_InitTypeDef DMA_InitStruct1; GPIO_InitTypeDef GPIO_InitStruct1; //配置GPIO GPIO_InitStruct1.GPIO_Pin = DMACNT_InitStruct->GPIO_Pin; GPIO_InitStruct1.GPIO_InitState = Bit_RESET; if(DMACNT_MODE_RISING == DMACNT_InitStruct->DMACNT_Mode) { GPIO_InitStruct1.GPIO_IRQMode = GPIO_IT_DMA_RISING; } else { GPIO_InitStruct1.GPIO_IRQMode = GPIO_IT_DMA_FALLING; } GPIO_InitStruct1.GPIOx = DMACNT_InitStruct->GPIOx; GPIO_InitStruct1.GPIO_Mode = GPIO_Mode_IPD; GPIO_Init(&GPIO_InitStruct1); //配置DMA DMA_InitStruct1.Channelx = DMACNT_InitStruct->DMA_Chl; DMA_InitStruct1.DMAAutoClose = DISABLE; DMA_InitStruct1.EnableState = ENABLE; DMA_InitStruct1.MinorLoopLength = 30000; switch((uint32_t)DMACNT_InitStruct->GPIOx) { case PTA_BASE: DMA_InitStruct1.PeripheralDMAReq = PORTA_DMAREQ; break; case PTB_BASE: DMA_InitStruct1.PeripheralDMAReq = PORTB_DMAREQ; break; case PTC_BASE: DMA_InitStruct1.PeripheralDMAReq = PORTC_DMAREQ; break; case PTD_BASE: DMA_InitStruct1.PeripheralDMAReq = PORTD_DMAREQ; break; case PTE_BASE: DMA_InitStruct1.PeripheralDMAReq = PORTE_DMAREQ; break; default : break; } DMA_InitStruct1.TransferBytes = 1; //配置目的地址传输参数 DMA_InitStruct1.DestBaseAddr = (uint32_t)&Dummy; DMA_InitStruct1.DestDataSize = DMA_DST_8BIT; DMA_InitStruct1.DestMajorInc = 0; DMA_InitStruct1.DestMinorInc = 0; //配置源地址传输参数 DMA_InitStruct1.SourceBaseAddr = (uint32_t)&Dummy; DMA_InitStruct1.SourceDataSize = DMA_SRC_8BIT; DMA_InitStruct1.SourceMajorInc = 0; DMA_InitStruct1.SourceMinorInc = 0; DMA_Init(&DMA_InitStruct1); } 有了初始化函数之后,我们就可以在主程序对药使用到的IO口进行DMA的初始化,因为DMA1通道我用来采集图像的数据,所以我用到的是DMA0和DMA2两个通道。 //C5 DMACNT_InitStruct1.DMACNT_Mode = DMACNT_MODE_FALLING; DMACNT_InitStruct1.DMA_Chl = DMA_CH0; //使用通道 0 DMACNT_InitStruct1.GPIOx = PTC; //PTC5 DMA1 用来摄像头 DMACNT_InitStruct1.GPIO_Pin = GPIO_Pin_5; DMACNT_Init(&DMACNT_InitStruct1); //A19 DMACNT_InitStruct1.DMACNT_Mode = DMACNT_MODE_FALLING; DMACNT_InitStruct1.DMA_Chl = DMA_CH2; //使用通道 2 DMACNT_InitStruct1.GPIOx = PTA; //PTA17 DMA1 用来摄像头 DMACNT_InitStruct1.GPIO_Pin = GPIO_Pin_17; DMACNT_Init(&DMACNT_InitStruct1); 对要使用的IO口进行初始化之后,便是对其寄存器数据的读取了。 //DMA脉冲计数 获得计数值 uint16_t DMACNT_GetValue(uint8_t DMA_Chl) { uint16_t DMA_Value = 0; DMA_Value = DMA_GetCurrDataCounter(DMA_Chl); DMA_SetCurrDataCounter(DMA_Chl,30000); return (30000-DMA_Value); } while(1) { Left_Speed = DMACNT_GetValue(DMA_CH0); Right_Speed = DMACNT_GetValue(DMA_CH2); UART_printf("Left_Speed is:%drn",Left_Speed); UART_printf("Right_Speed is:%drnrn",Right_Speed); DelayMs(500); } 测速度是一大重点,而另外一大重点显然是侧正反转。测正反转是直立车原地平衡中不可或缺的一部分。 测正反转的电路和原理如下图: 分辨正反转是根据A相和B相上升沿到来的顺序分别得,结合上图和按照自己查到的一些资料,分许一下该图。 该图的下半部分是电路图,这是钟控触发器,这个触发器有四个引脚,右边两个是互逆的2个输出,D引脚接A相CLK引脚接B相,CLK引脚即为时钟线,当B相输出为上升沿的时候触发,将A相此时的输出给Q端口。当B相输出为其他时,不触发。 举例: a.见上图的上半部分。如果蓝色为A相,黄色为B相,在红色虚线位置时,B相输出上升沿,CLK采集触发器触发。此时A相输出为高,则Q输出为高,因此当单片机检测到Q输出为高时,A相的上升沿先于B相的上升沿到来,所以为正转。 b.如果蓝色为B相,黄色为A相,在红色虚线前半个周期时,B相输出上升沿,CLK采集触发器触发。此时A相输出为低,则Q输出为低,因此当单片机检测到Q输出为低时,A相的上升沿后于B相的上升沿到来,所以反转。 |
|
|
|
只有小组成员才能发言,加入小组>>
2393 浏览 0 评论
8930 浏览 4 评论
36520 浏览 19 评论
4990 浏览 0 评论
24351 浏览 34 评论
1388浏览 2评论
1642浏览 1评论
2041浏览 1评论
1456浏览 0评论
401浏览 0评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-26 04:01 , Processed in 1.187264 second(s), Total 48, Slave 41 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号