首页 > 其他 > 详细

飞思卡尔 shut down (三)智能车的测速(K60 欧姆龙500线编码器DMA测速)

时间:2014-04-14 01:30:10      阅读:1166      评论:0      收藏:0      [点我收藏+]

转载请注明出处:http://blog.csdn.net/lxk7280


最近两天整天朦朦胧胧的,也不知道做了些什么,时间真的是在不自觉中就溜走了,只是早上起来一个贪玩的念头,一天就会没了,甚至只是晚上一个想看一部电影的念头,就会导致第二天一整天没精神做事。自制力是一个人最重要的品质之一,一个念头的影响是很大的。昨天在CSDN上看到July大牛的一句话:"一个有毅力有内心驱动力的人,一旦认定该做什么事之后,便会不顾规则,且义无反顾,不顾一切的去干。"  - 引以为戒。

       下面说说我在使用DMA模块对编码器测速的经验吧:

第一件要注意的事情是在安装编码器的时候一定要按照该图,在信号线接上上拉电阻。

编码器的引脚图上拉电阻的连接方式如图:

         bubuko.com,布布扣          bubuko.com,布布扣

 对于不接上拉电阻的后果,我表示经历过了。下面给出同样正确的程序,在两种情况下,K60采集并发回的数据:      

      bubuko.com,布布扣           bubuko.com,布布扣


上拉电阻对编码器信号造成什么影响?

不加上拉电阻时,编码器的信号线输出是小尖波,而加上上拉电阻后,编码器的信号输出为方波。前者K60无法检测脉冲,更不谈测速度一说了。



第二件事就是测速的编程,要变成首先要明白测速的方法要用到哪个模块。测速的方法有很多种,如:在PIT定时中读取LPTM脉冲计数(缺点是无法测两路编码器)、FTM正交解码、DMA测速等。

   LPTM的缺点是有两个引脚,但是同时只有一路能使用,因此无法测两路编码器。如图:
           bubuko.com,布布扣

我使用的是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:%d\r\n",Left_Speed);
	UART_printf("Right_Speed is:%d\r\n\r\n",Right_Speed);
	DelayMs(500);
}





飞思卡尔 shut down (三)智能车的测速(K60 欧姆龙500线编码器DMA测速),布布扣,bubuko.com

飞思卡尔 shut down (三)智能车的测速(K60 欧姆龙500线编码器DMA测速)

原文:http://blog.csdn.net/lxk7280/article/details/23480353

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!