论坛» DIY与开源设计» 电子DIY

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

助工
2015-09-27 00:30 1楼

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

目录

基础实验部分

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

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

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

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

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

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

七.USART的通讯(已更新)

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

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

高级实验部分


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

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

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

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

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

助工
2015-09-27 00:56 2楼

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

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






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

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


效果如下视频:


下面就开始进入学习了


视频地址:http://player.youku.com/player.php/sid/XMTM1MjUxOTk4MA==/v.swf
助工
2015-09-27 01:29 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 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 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 6楼

五.按键控制LED灯的亮灭

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


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


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

好吧,上代码按键.rardelay.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 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 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 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 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 跳转至

回复

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