这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » STM32平衡小车学习进程 ——liushidesuiyue

共14条 1/2 1 2 跳转至

STM32平衡小车学习进程 ——liushidesuiyue

助工
2015-09-27 00:30:17     打赏

小车已经吃灰了好久,之前也没学过STM32,就从这里开始学习吧(小白写的东西简单大家理解一下,可能有借鉴其他网友的,但每一个都是自己实践过可以才发上来的)

目录

基础实验部分

一.小车的开箱以及遇到的问题(已更新)

二.建立一个工程(已更新)

三.点亮一个LED灯(已更新)

四.LED灯利用systick定时器的延时闪烁(已更新)

五.按键控制LED灯的亮灭(已更新)

六.采用PWM驱动电机(已更新)

七.USART的通讯(已更新)

八.编码器读取电机的转速(已更新)

九.无线通讯实验(已更新)

高级实验部分


一.PID参数的调试(已更新)

二.直立时小车保持静止(已更新)

三.小车绕8字行走(已更新)

四.多传感器数据融合(已更新)

.实现小车自主避障
六.实现小车利用线性CCD巡线
七.实现体感控制
八.撰写APP实现对小车的数据和状态进行监控



助工
2015-09-27 00:56:23     打赏
2楼

一.小车的开箱以及遇到的问题

开箱,太久了我的箱都不见了,小车的安装也是满简单的,安装时只要注意电池放的方向还有电机线的方向就行的(放对方向就没有必要去剪掉扎带了,懒人就是这样...)






安装完了之后打开开关就可以正常使用了,默认带的程序效果已经不错了

可惜在买了之后的一段时间吃灰之后,小车就出现问题了,开启时小车只能对一边的倾斜作出调整,倾向另外一边时没有任何的输出调整(已经是两次了,第一次的卖家帮忙弄好的,卖家人好),第二次就知道原因了,主控芯片的引脚虚焊了,当向下轻压芯片时小车能够正常两边调整,好吧,拿个电烙铁焊一下就好了,小问题(就是图中的st芯片)


效果如下视频:


下面就开始进入学习了


视频地址:http://player.youku.com/player.php/sid/XMTM1MjUxOTk4MA==/v.swf

助工
2015-09-27 01:29:39     打赏
3楼

二.建立一个工程

    由于是看着STM32自学笔记建立工程的,这里就按照他的方法吧

(1)先从网上下载ST公司的STM32固件库STM32f10x_fw_archive.rar然后解压

(2)新建6个文件夹分别为boot、library、src、obj、list、interrupt,将对应的文件放入到对应的文件夹中,如下目录结构:

(3)新建工程和选择芯片型号...(楼主比较懒所以就简单带过,重点说下自己在建立中遇到的问题把)

建立过程中记得添加路径,不然会找不到库文件(includes paths选项右边的省略号那里)


添加完之后应该如下


最好把Define那里写入STM32F10X_HD,USE_STDPERIPH_DRIVER(好像不加有很多问题后面)


有比楼主懒的那就下载分享的那个文件把,都拉好了STM32_FW.rar



助工
2015-09-27 01:47:16     打赏
4楼

三.点亮一个LED灯

查看原理图可知小车上有两个led灯,红灯是电源灯,蓝灯是工作灯,其接在PB8上,也就是GPIOB的第八个管脚上(是不是画反了!)


下面就直接看程序把LED点亮.rar需要下载的在这里

#include "stm32f10x_lib.h"
void GPIO_Configuration(void);
int main(void)
{	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//ʹÄÜGPIOB
	GPIO_Configuration();//GPIO定义
	GPIO_ResetBits(GPIOB,GPIO_Pin_8);//拉低GPIO_Pin_8
}
void GPIO_Configuration(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;//选择引脚
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;//设置速度
  GPIO_InitStructure.GPIO_Mode =GPIO_Mode_Out_PP;//输出模式
  GPIO_Init(GPIOB, &GPIO_InitStructure);
}

 效果如下



助工
2015-09-27 02:02:00     打赏
5楼

四.LED灯利用systick定时器的延时闪烁

这是一个24位的系统节拍定时器system tick timer,SysTick,具有自动重载和溢出中断功能,所有基于Cortex_M3处理器的微控制器都可以由这个定时器获得一定的时间间隔。Systick就是一个定时器而已,只是它放在了NVIC中,主要的目的是为了给操作系统提供一个硬件上的中断(号称滴答中断)。代码下载闪烁LED.rar

视频地址:http://player.youku.com/player.php/sid/XMTM0NTc1ODI4NA==/v.swf

上面的就是视频效果

直接看代码吧

delay.c

#include "stm32f10x_systick.h"
	 
static u8  fac_us=0;//微秒
static u16 fac_ms=0;//毫秒

void delay_init(u8 SYSCLK) //初始化延时函数
{
	SysTick->CTRL&=0xfffffffb;//bit2清0,选择外部时钟  HCLK/8
	fac_us=SYSCLK/8;		    
	fac_ms=(u16)fac_us*1000;
}				
				    
void delay_ms(u16 nms) //毫秒的延时
{	 		  	  
	u32 temp;		   
	SysTick->LOAD=(u32)nms*fac_ms;
	SysTick->VAL =0x00;           //清空计数器
	SysTick->CTRL=0x01 ;          //开始倒数
	do
	{
		temp=SysTick->CTRL;
	}
	while(temp&0x01&&!(temp&(1<<16)));//等待时间到达 SysTick->CTRL=0x00;       //关闭计数器
	SysTick->VAL =0X00;       //清空计数器	    
}   
	    								   
void delay_us(u32 nus)
{		
	u32 temp;	    	 
	SysTick->LOAD=nus*fac_us; 		 
	SysTick->VAL=0x00;        //清空计数器
	SysTick->CTRL=0x01 ;      //开始倒数 
	do
	{
		temp=SysTick->CTRL;
	}
	while(temp&0x01&&!(temp&(1<<16)));//等待时间到达 SysTick->CTRL=0x00;       //关闭计数器
	SysTick->VAL =0X00;       //清空计数器
}


delay.h


#include "stm32f10x_type.h"
#ifndef __DELAY_H
#define __DELAY_H 
void delay_init(u8 SYSCLK);
void delay_ms(u16 nms);
void delay_us(u32 nus);
void get_ms(unsigned long *count);
#endif


main.c


#include "stm32f10x_lib.h"
#include "delay.h"
void GPIO_Configuration(void);
int main(void)
{	
	delay_init(72);//初始化延时函数
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//使能
	GPIO_Configuration();
	while(1)
	{
	  GPIO_ResetBits(GPIOB,GPIO_Pin_8);//点亮
		delay_ms(50);
		GPIO_SetBits(GPIOB,GPIO_Pin_8);//熄灭
		delay_ms(50);
}

}

void GPIO_Configuration(void)//GPIO定义
{
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
  GPIO_InitStructure.GPIO_Mode =GPIO_Mode_Out_PP;
  GPIO_Init(GPIOB, &GPIO_InitStructure);
}

助工
2015-09-27 10:12:52     打赏
6楼

五.按键控制LED灯的亮灭

按键如原理图,PB5口与按键连接,读取PB5的电平就可以知道按键的状态


按键延时程序主要就先检测按键是否按下,接着延时消抖,再次检测按键是否按下,如果真的按下就返回相应的值,注意松手检测。效果如下:


视频地址:http://player.youku.com/player.php/sid/XMTM0NTc1NDg5Ng==/v.swf

好吧,上代码按键.rar delay.c同上,就不再赘述

#include "stm32f10x_lib.h"
#include "stm32f10x_systick.h"
#include "delay.h"
#define KEY0  GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_5)//宏定义读取GPIOB5的电平
int i,j;
void KEY_Scan(void);//按键扫描声明
void GPIO_Configuration(void);

 	
int main(void)
{	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//ʹÄÜPORTB,PORTEʱÖÓ
	delay_init(72);//初始化延时函数
	GPIO_Configuration();//GPIO的配置
	while(1)
	{
		
	KEY_Scan();//键盘扫描
		if(i==1)
		GPIO_WriteBit(GPIOB,GPIO_Pin_8,(BitAction)(1-(GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_8))));//翻转电平
}
}
void KEY_Scan(void)
{	 
	if(KEY0==0)
	{
		delay_ms(10);//延时消抖
		j=0;
		if(KEY0==0)
		{
			//i=1;
		while(j<50&&(!KEY0))//松手检测
		{
			delay_ms(1);
			j++;
}
i=1;
		}
		
	}	else	
	i=0;

}
void GPIO_Configuration(void)//
{
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
  GPIO_InitStructure.GPIO_Mode =GPIO_Mode_Out_PP;
  GPIO_Init(GPIOB, &GPIO_InitStructure);
	
}

 


结束按键实验


助工
2015-09-27 10:49:43     打赏
7楼

六.采用PWM驱动电机

在实验之前,我们先来了解一下小车驱动的相关知识吧。

对于电机的转速调整,我们是采用脉宽调制(PWM)办法,控制电机的时候,电源并非连续地向电机供电,而是在一个特定的频率下以方波脉冲的形式提供电能。不同占空比的方波信号能对电机起到调速作用,这是因为电机实际上是一个大电感,它有阻碍输入电流和电压突变的能力,因此脉冲输入信号被平均分配到作用时间上,这样,改变在输入方波的占空比就能改变加在电机两端的电压大小,从而改变了转速。

而我们单片机CPU的IO引脚无法提供足够的电流,所以需要通过一个驱动电路实现对直流电机的驱动。小车采用的是TB6612。驱动电路的核心是一组桥式开关,通过控制四个开关的导通与否决定电机是正转还是反转还是制动。


TB6612FNG这款驱动芯片的真值表如下:


该器件工作时STBY引脚置为高电平;IN1和IN2不变,调整PWM引脚的输入信号可进行电机单向速度控制;置PWM引脚为高电平,并调整IN1和IN2的输入信号可进行电机双向速度控制。

那么,程序中该如何设置呢?代码中通过TIM3作为电机的PWM源信号产生,并且都工作早PWM1模式下,而在PWM1模式下,变化的计数器不断与CCRy进行比较。假设计数器采用加计数方式,当计数器的值TIMx_CNT小于TIMx_CCRy时,PWM信号保持高电平。当TIMx_CNT不断增加,直到大于TIMx_CCRy时,PWM变成低电平。TIMx_CNT继续增加,当达到TIMx_ARR预设的值后,复位返回0值。

简单地理解就是,TIM3->ARR决定了PWM信号的周期(TIM3->ARR=arr;),TIM3->CCR4和TIM3->CCR3决定了PWM信号的占空比(在我的代码中是这样的)电机驱动.rar


视频地址:http://player.youku.com/player.php/sid/XMTM0NjA1NzUzMg==/v.swf

代码如下:

main.c


#include "main.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_tim.h"
#include "stm32f10x_rcc.h"
void SystemInit (void)
{
  /* Reset the RCC clock configuration to the default reset state(for debug purpose) */
  /* Set HSION bit */
  RCC->CR |= (unsigned int)0x00000001;

  /* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */
}
void MiniBalance_Motor_Init(void)
{
	RCC->APB2ENR|=1<<3; //PORTB使能输出 GPIOB->CRH&=0X0000FFFF;   //PORTB12 13 14 15推挽输出
	GPIOB->CRH|=0X22220000;   //PORTB12 13 14 15推挽输出
}
void MiniBalance_PWM_Init(u16 arr,u16 psc)
{		 					 
	MiniBalance_Motor_Init(); //初始化驱动电机所需IO
	RCC->APB1ENR|=1<<1; //TIM3使能 RCC->APB2ENR|=1<<3; //PORTB时钟使能 GPIOB->CRL&=0XFFFFFF00;   //PORTB0 1复用输出
	GPIOB->CRL|=0X000000BB;   //PORTB0 1复用输出
	TIM3->ARR=arr;//计数器自动重装值
	TIM3->PSC=psc;//预分频器不分频
	TIM3->CCMR2|=6<<12;//CH4 PWM1模式 TIM3->CCMR2|=6<<4; //CH3 PWM1模式 TIM3->CCMR2|=1<<11;//CH4预装载使能 TIM3->CCMR2|=1<<3; //CH3预装载使能 TIM3->CCER|=1<<12; //CH4输出使能 TIM3->CCER|=1<<8; //CH3输出使能 TIM3->CR1=0x8000;  //ARPE使能
	TIM3->CR1|=0x01;   //使能定时器3									  
} 
int main(void)
{
	SysTick->CTRL&=0xfffffffb;//bit2清空,选择外部时钟HCLK/8
	SystemInit();
	MiniBalance_PWM_Init(3599,0); 
	while(1)

{
	GPIOB->ODR &= ~(1<<8); PWMA = 3000; PWMB = 3000; GPIO_ResetBits(GPIOB,GPIO_Pin_15);//AIN2=0 GPIO_SetBits(GPIOB,GPIO_Pin_14);//AIN1=1 逆时针 GPIO_ResetBits(GPIOB,GPIO_Pin_13);//BIN1=0 GPIO_SetBits(GPIOB,GPIO_Pin_12);//BIN2=1 顺时针 } } 

main.h

#define GPIOA_ODR_Addr    (GPIOA_BASE+12) //0x4001080C 
#define GPIOB_ODR_Addr    (GPIOB_BASE+12) //0x40010C0C 
#define GPIOC_ODR_Addr    (GPIOC_BASE+12) //0x4001100C 
#define GPIOD_ODR_Addr    (GPIOD_BASE+12) //0x4001140C 
#define GPIOE_ODR_Addr    (GPIOE_BASE+12) //0x4001180C 
#define GPIOF_ODR_Addr    (GPIOF_BASE+12) //0x40011A0C    
#define GPIOG_ODR_Addr    (GPIOG_BASE+12) //0x40011E0C    

#define GPIOA_IDR_Addr    (GPIOA_BASE+8) //0x40010808 
#define GPIOB_IDR_Addr    (GPIOB_BASE+8) //0x40010C08 
#define GPIOC_IDR_Addr    (GPIOC_BASE+8) //0x40011008 
#define GPIOD_IDR_Addr    (GPIOD_BASE+8) //0x40011408 
#define GPIOE_IDR_Addr    (GPIOE_BASE+8) //0x40011808 
#define GPIOF_IDR_Addr    (GPIOF_BASE+8) //0x40011A08 
#define GPIOG_IDR_Addr    (GPIOG_BASE+8) //0x40011E08 
 
//IO操作
#define PAout(n)   BIT_ADDR(GPIOA_ODR_Addr,n)  //输出
#define PAin(n)    BIT_ADDR(GPIOA_IDR_Addr,n)  //输入

#define PBout(n)   BIT_ADDR(GPIOB_ODR_Addr,n)  
#define PBin(n)    BIT_ADDR(GPIOB_IDR_Addr,n)  

#define PCout(n)   BIT_ADDR(GPIOC_ODR_Addr,n) 
#define PCin(n)    BIT_ADDR(GPIOC_IDR_Addr,n) 

#define PDout(n)   BIT_ADDR(GPIOD_ODR_Addr,n)
#define PDin(n)    BIT_ADDR(GPIOD_IDR_Addr,n)  

#define PEout(n)   BIT_ADDR(GPIOE_ODR_Addr,n) 
#define PEin(n)    BIT_ADDR(GPIOE_IDR_Addr,n) 

#define PFout(n)   BIT_ADDR(GPIOF_ODR_Addr,n)  
#define PFin(n)    BIT_ADDR(GPIOF_IDR_Addr,n) 

#define PGout(n)   BIT_ADDR(GPIOG_ODR_Addr,n)  
#define PGin(n)    BIT_ADDR(GPIOG_IDR_Addr,n)  
#define PWMA   TIM3->CCR4
#define AIN2   PBout(15)
#define AIN1   PBout(14)
#define BIN1   PBout(13)
#define BIN2   PBout(12)
#define PWMB   TIM3->CCR3

 


电机驱动结束





 



助工
2015-09-27 14:32:52     打赏
8楼

七.USART的通讯

     当你需要设计一个上位机是串口通信必然是最基本的组件,STM32固件库为串口通信的操作提供了很多有用的函数,使得我们在使用串口时不必关注底层硬件的操作,使用相关函数即可,下面介绍串口操作的要点。串口发送.rar

从原理图可以看出串口1连接PA9和PA10


     在代码中先对串口的IO口配置和波特率等设置

void usart1_init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; 
 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//选择PA9为复用输出
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOA, &GPIO_InitStructure);    
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//PA10为浮空输入
  GPIO_Init(GPIOA, &GPIO_InitStructure);
	USART_InitStructure.USART_BaudRate = 115200; //波特率设置
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长设置
	USART_InitStructure.USART_StopBits = USART_StopBits_1;//1位的停止位
	USART_InitStructure.USART_Parity = USART_Parity_No ;//无奇偶校验
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//不启用硬件流控制
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;	//使能发送和接受功能
	USART_Init(USART1, &USART_InitStructure);
  	USART_Cmd(USART1, ENABLE);

}



如果要使用printf函数打印信息,需要加fputc函数,就需要对printf函数重定向到串口

int fputc(int ch, FILE *f)
{
	USART1->DR=(u8)ch;
	while((USART1->SR&0X40)==0);
	return ch;
}

 

main函数中的调用


int main(void)
{
	int i=0;
	usart1_init();
	while(1)
	{
	printf("\r\nEEPW-liushidesuiyue\r\n");
		for(i=0;i<30000;i++); //短暂延时,保证发送完全
	
}
}

 



在options for target中一定要勾选use Microlib,否则即使程序代码是对的也不会像串口发送消息。


设置完下载进去就可以了


视频如下



视频地址:http://player.youku.com/player.php/sid/XMTM0NjE5NTE4OA==/v.swf

串口实验结束


助工
2015-09-27 22:24:24     打赏
9楼

八.编码器读取电机的转速

直流电机编码器的作用,主要是测定电机的速度,为控制器提供反馈信号。是半闭环控制的检测元件。编码器读取.rar








从原理图中可以看出,编码器用到了单片机的PA0、PA1、PB6、PB7接口,还用定时器1,2,4,定时器1用来进行50ms的中断任务执行,定时器2和4分别对编码器1和2产生溢出中断,完成对编码器脉冲的计数。代码主要包括oled屏的显示和定时器、编码器的设置。

效果如下


先上定时器的设置:

timer.c

#include "timer.h"
#include "math.h"

void TIM2_IRQHandler(void)//编码器读取中断
{ 		    		  			    
	if(TIM2->SR&0X0001)//溢出中断
	{
			    				   				     	    	
	}				   
	TIM2->SR&=~(1<<0);// 清除中断标志位 } void TIM4_IRQHandler(void)//编码器读取中断 { u16 tsr; tsr=TIM4->SR;	
	if(tsr&0X0001)
	{
																				
	}				   
	TIM4->SR&=~(1<<0); } void Encoder_Init2(void)//编码器初始化 { /* TIM2 clock source enable */ RCC->APB1ENR|=1<<0; //TIM2ʱÖÓʹÄÜ /* Enable GPIOA, clock */ RCC->APB2ENR|=1<<2; //ʹÄÜPORTAʱÖÓ /* Configure PA.00,01 as encoder input */ GPIOA->CRL&=0XFFFFFFF0;//PA0
	GPIOA->CRL|=0X00000004;
	GPIOA->CRL&=0XFFFFFF0F;//PA1
	GPIOA->CRL|=0X00000040;

	/* Enable the TIM2 Update Interrupt */
	TIM2->DIER|=1<<0; TIM2->DIER|=1<<6; MY_NVIC_Init(1,3,TIM2_IRQChannel,1); /* Timer configuration in Encoder mode */ TIM2->PSC = 0x0;
	TIM2->ARR = ENCODER_TIM_PERIOD-1;
	TIM2->CR1 &=~(3<<8); TIM2->CR1 &=~(3<<5); TIM2->CCMR1 |= 1<<0; //CC1S='01' TIM2->CCMR1 |= 1<<8; //CC2S='01' TIM2->CCER &= ~(1<<1); //CC1P='0' TIM2->CCER &= ~(1<<5); //CC2P='0' TIM2->CCMR1 |= 3<<4; // IC1F='1000' TIM2->SMCR |= 3<<0; //SMS='011' TIM2->CNT = COUNTER_RESET;
	TIM2->CR1 |= 0x01;   
}

void Encoder_Init(void)//编码器初始化
{
	/* TIM4 clock source enable */ 
	RCC->APB1ENR|=1<<2; //TIM3使能 /* Enable GPIOB, clock */ RCC->APB2ENR|=1<<3; /* Configure PB.06,07 as encoder input */ GPIOB->CRL&=0XF0FFFFFF;//PB6
	GPIOB->CRL|=0X08000000;
	GPIOB->CRL&=0X0FFFFFFF;//PB7
	GPIOB->CRL|=0X40000000;

	/* Enable the TIM3 Update Interrupt */
	TIM4->DIER|=1<<0; TIM4->DIER|=1<<6; MY_NVIC_Init(1,3,TIM4_IRQChannel,1); /* Timer configuration in Encoder mode */ TIM4->PSC = 0x0;
	TIM4->ARR = ENCODER_TIM_PERIOD-1;
	TIM4->CR1 &=~(3<<8); TIM4->CR1 &=~(3<<5); TIM4->CCMR1 |= 1<<0; //CC1S='01' IC1FP1Ó³Éäµ½TI1 TIM4->CCMR1 |= 1<<8; //CC2S='01' IC2FP2Ó³Éäµ½TI2 TIM4->CCER &= ~(1<<1); //CC1P='0' TIM4->CCER &= ~(1<<5); //CC2P='0' TIM4->CCMR1 |= 3<<4; // IC1F='1000' TIM4->SMCR |= 3<<0; //SMS='011' TIM4->CNT = COUNTER_RESET;
	TIM4->CR1 |= 0x01;  
}


//定时中断初始化
void Timer1_Init(u16 arr,u16 psc)  
{  
	RCC->APB2ENR|=1<<11;//TIM2时钟使能 TIM1->ARR=arr;  //自动重装初值   
	TIM1->PSC=psc;  //
	TIM1->DIER|=1<<0; //允许更新中断 TIM1->DIER|=1<<6; //允许触发中断 TIM1->CR1|=0x01;   
	MY_NVIC_Init(1,3,TIM1_UP_IRQChannel,1);
}  

void MiniBalance_PWM_Init(u16 arr,u16 psc)
{		 					 
	RCC->APB1ENR|=1<<1; //TIM3ʱÖÓʹÄÜ RCC->APB2ENR|=1<<3; //PORTBʱÖÓʹÄÜ GPIOB->CRL&=0XFFFFFF00;   //PORTB0 1¸´ÓÃÊä³ö
	GPIOB->CRL|=0X000000BB;   //PORTB0 1¸´ÓÃÊä³ö
	GPIOB->CRH&=0X0000FFFF;   //PORTB12 13 14 15ÍÆÍìÊä³ö
	GPIOB->CRH|=0X22220000;   //PORTB12 13 14 15ÍÆÍìÊä³ö
	TIM3->ARR=arr;//É趨¼ÆÊýÆ÷×Ô¶¯ÖØ×°Öµ 
	TIM3->PSC=psc;//Ô¤·ÖƵÆ÷²»·ÖƵ
	TIM3->CCMR2|=6<<12;//CH4 PWM2ģʽ TIM3->CCMR2|=6<<4; //CH3 PWM2ģʽ TIM3->CCMR2|=1<<11;//CH4ԤװÔØʹÄÜ TIM3->CCMR2|=1<<3; //CH3ԤװÔØʹÄÜ TIM3->CCER|=1<<12; //CH4Êä³öʹÄÜ TIM3->CCER|=1<<8; TIM3->CR1=0x8000; 
	TIM3->CR1|=0x01;   									  
} 
//NVIC初始化
void MY_NVIC_Init(u8 NVIC_PreemptionPriority,u8 NVIC_SubPriority,u8 NVIC_Channel,u8 NVIC_Group)	 
{ 
	u32 temp;	
	u8 IPROFFSET=NVIC_Channel%4;//ÔÚ×éÄÚµÄÆ«ÒÆ
	IPROFFSET=IPROFFSET*8+4;    //µÃµ½Æ«ÒƵÄÈ·ÇÐλÖÃ
	MY_NVIC_PriorityGroupConfig(NVIC_Group);//ÉèÖ÷Ö×é
	temp=NVIC_PreemptionPriority<<(4-NVIC_Group); temp|=NVIC_SubPriority&(0x0f>>NVIC_Group);
	temp&=0xf;//È¡µÍËÄλ
	if(NVIC_Channel<32)NVIC->ISER[0]|=1AIRCR; 
	temp&=0X0000F8FF; 
	temp|=0X05FA0000; 
	temp|=temp1;	   
	SCB->AIRCR=temp;     	  				   
}




通过该函数在5ms的中断服务中读取编码器的值

void TIM1_UP_TIM16_IRQHandler(void)  
{    
	if(TIM1->SR&0X0001)//5ms定时中断
	{   
		  TIM1->SR&=~(1<<0); //清除定时器1的中断标志位 readEncoder(); //读取编码器的值 } 


通过readEconder()读取编码器的值


void readEncoder(void)
{
	  u16 Encoder_L,Encoder_R;       //左右编码器的脉冲计数
		Encoder_R = TIM4 -> CNT;       //获取编码器1的计数
		TIM4 -> CNT=0;                 //计数器清零
	  Encoder_L= TIM2 -> CNT;        //获取编码器2的计数
	  TIM2 -> CNT=0;	               //计数器清零
		if(Encoder_L>32768)  Encoder_Left=Encoder_L-65000; else  Encoder_Left=Encoder_L;  
	  if(Encoder_R>32768)  Encoder_Right=Encoder_R-65000; else  Encoder_Right=Encoder_R;
	 	Encoder_Left=-Encoder_Left;
}




主要就是这几个函数,注意添加编码器的读取中断TIM2_IRQHandler()TIM4_IRQHandler(),原先忘了添加一直在那里读取不到编码器的计数好久....

视频效果



视频地址:http://player.youku.com/player.php/sid/XMTM0NjU1MDUzMg==/v.swf

好了,编码器读取的实验就结束了


助工
2015-10-05 16:53:34     打赏
10楼

九.无线通讯实验

         蓝牙连接的是串口3,如图


蓝牙在串口接受中断中:

void USART3_IRQHandler(void)
{	
	if(USART3->SR&(1<<5))//接受中断
	{	  
	  static	int uart_receive=0;//蓝牙接受相关的变量
		uart_receive=USART3->DR; 
		if(uart_receive<10)    mode_data[0]=uart_receive;

			if((mode_data[0]==six_data_2[0]
			&&mode_data[1]==six_data_2[1]
			&&mode_data[2]==six_data_2[2]
			&&mode_data[3]==six_data_2[3])
			||(mode_data[0]==six_data_1[0]
			&&mode_data[1]==six_data_1[1]
			&&mode_data[2]==six_data_1[2]
			&&mode_data[3]==six_data_1[3]))
		{	
			Flag_Stop=!Flag_Stop;
			mode_data[0]=0;	mode_data[1]=0;	mode_data[2]=0;	mode_data[3]=0;
		}
		if(uart_receive==0x00)	Flag_Qian=0,Flag_Hou=0,Flag_Left=0,Flag_Right=0;//////////////刹车
		if(uart_receive==0x01)	Flag_Qian=1,Flag_Hou=0,Flag_Left=0,Flag_Right=0;//////////////前
		if(uart_receive==0x05)	Flag_Qian=0,Flag_Hou=1,Flag_Left=0,Flag_Right=0;//////////////后
		else if(uart_receive==0x02||uart_receive==0x03||uart_receive==0x04)	
													Flag_Qian=0,Flag_Hou=0,Flag_Left=0,Flag_Right=1;
		else if(uart_receive==0x06||uart_receive==0x07||uart_receive==0x08)	
													Flag_Qian=0,Flag_Hou=0,Flag_Left=1,Flag_Right=0;

		mode_data[7]=mode_data[6];
		mode_data[6]=mode_data[5];
		mode_data[5]=mode_data[4];
		mode_data[4]=mode_data[3];
		mode_data[3]=mode_data[2];
		mode_data[2]=mode_data[1];
		mode_data[1]=mode_data[0];
	}  											 
} 

 



     从APP发送数据,串口接收发送中断,对接收到的数据进行匹配并进行相应的动作处理。 


共14条 1/2 1 2 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]