导读:《麦克纳姆轮小车制作》专栏文章是博主在自学stm32期间所做的学习笔记,秉持着“Learn by doing”的学习理念,博主在学习完stm32的相关基础知识后,便开始了上手实战。在小车的制作过程中,从主控板电路设计、PCB打板制作、车模组装到软件设计皆由博主亲手完成,期间也经历了很多困难,但最终也都一一解决,更重要的是,实践的过程加深了博主对于stm32的理解,也让博主体会到了学习的成就感,受益良多。为了帮助和我一样的初学者,现将当时的学习笔记做了梳理,希望能有所帮助。学海无涯,让我们一起进步吧!!!
一、左右轮PWM波的产生
我是利用定时器的PWM模式产生的PWM波,具体可参考我的博客: STM32之通用定时器输出PWM波,这里我只贴出代码:
#include "stm32f10x.h"
//freq,PWML,PWMR均在主函数中定义
extern u32 freq;//频率
extern u8 PWML;//左电机PWM
extern u8 PWMR;//右电机PWM
void PWM2_Init(void)//利用TIM2的通道1(左电机)和通道2(右电机)产生PWM波
{
u32 arr;
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
arr = 1000000 / freq;//计算频率对应的周期值(计数值)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//强推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
TIM_TimeBaseStructure.TIM_Prescaler = 72-1;//72分频
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
TIM_TimeBaseStructure.TIM_Period = arr - 1;//周期值
TIM_TimeBaseStructure.TIM_ClockDivision = 0;//不分频
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);//TIM2定时器
//对通道1和通道2配置为PWM输出模式
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;//输出模式配置为PWM2模式
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;//低极性
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//使能输出状态
TIM_OCInitStructure.TIM_Pulse = (arr-1) * PWML / 100;//占空比
TIM_OC1Init(TIM2, &TIM_OCInitStructure);//TIM2_CH1
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;//输出模式配置为PWM2模式
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;//低极性
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//使能输出状态
TIM_OCInitStructure.TIM_Pulse = (arr-1) * PWMR / 100;//占空比
TIM_OC2Init(TIM2, &TIM_OCInitStructure);//TIM2_CH2
TIM_Cmd(TIM2, ENABLE);//使能TIM2
}
二、利用按键调节PWM(可加可减)
1、首先要写一个按键的底层,另外按键扫描函数keyscan()
是要放在定时器中断里,每2ms扫描一次的,所以还要写一个定时器定时2ms的函数,然后再写一个定时器中断,这一点和51是一样的,具体可参考:STM32之按键+蜂鸣器,STM32之定时器配置,不要忘记在key.h
文件中定义你的按键引脚:
#define KEY1 GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_12);//加
#define KEY2 GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_9);//减
#define KEY3 GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_15);//转换(判断改变值是PWML还是PWMR)
2、在主函数main.c
中写加减PWM的函数:
void AddPWM(u8 *PWM)
{
if(*PWM < 90)
{
*PWM += 5;
}
else
{
*PWM = 0;
}
}
void SubPWM(u8 *PWM)
{
if(*PWM > 0)
{
*PWM -= 5;
}
else
{
*PWM = 90;
}
}
这里我用了指针,可以简化代码。
3、按键动作函数KeyAction()
void KeyAction(u8 keycode)
{
if(keycode == 1)//按下按键KEY1
{
if(flagPWM == 0)
{
AddPWM(&PWML);
}
else
{
AddPWM(&PWMR);
}
PWM2_Init();//每次按下按键才进行PWM的初始化!!!
}
else if(keycode == 2)//按下按键KEY2
{
if(flagPWM == 0)
{
SubPWM(&PWML);
}
else
{
SubPWM(&PWMR);
}
PWM2_Init();//每次按下按键才进行PWM的初始化!!!
}
else if(keycode == 3)//按下按键KEY3
{
flagPWM ^= 1;
}
}
说明:
关于
PWM2_Init();
函数: 不能在while(1)中初始化!!!,只能是在每次按下按键时才初始化(就是将改变后的PWM写入初始化函数),否则不能输出准确的PWM波(实际上我用逻辑分析仪观察的结果是根本观测不到PWM波),这一点一定要注意!!!!
4、最后可以在主函数 while(1)
里写一个小车前进函数,进行调试,注意在while(1)
外写上PWM的初始化函数PWM2_Init();
。(当然,也可以加一个显示屏,直接把参数显示到显示屏上面,会更加直观,我加的是oled,另外的文章里我会详细写这个东东)
#define LED_ON PAout(12)=0 //开灯
#define LED_OFF PAout(12)=1 //关灯
int main(void)
{
GPIO_IN1_IN8();//电机驱动引脚初始化
GPIO_Led_Init();//led初始化,这是我加的指示灯
KeyInit();
PWM2_Init();
TIM3_Int_Init(2000,72);//定时2ms
LED_OFF;
while (1)
{
KeyDriver();
motor(M_FOR, M_FOR, M_FOR, M_FOR);//一个前进函数
}
}
说明:
- emmm,关于下面的写法不理解的可以看看:STM32变量定义及位带操作,关于位带操作的,一种更方便的直接操作GPIO口的方法,这个跟51比较像。
#define LED_ON PAout(12)=0 //开灯
一点感受: 最后谈谈我的一点感受吧,当然我是以一个初学者的角度来说的,大一的时候我做过一个51的简易红外寻迹小车,当时代码写的真的很水很水,PWM波输出甚至使用delay延时函数写的,但是最后也算是跑起来了,当时真的是属于没有一点学习方法,调车的时候也是瞎调的,现在想想大一的时候做的好像都是一些无用功。这次调车的时候,我学会了借助一些电子仪器,比如说逻辑分析仪,来直观地看到输出的PWM波,然后再根据出来的波形修改程序,直到找的问题出在哪儿,我会去借助不同的开发板来排除硬件问题,然后我会自己去想需求,根据想出的需求去网上找那一部分的资料,然后自己写出来,当然刚开始比较慢,但是功能实现的时候会很有成就感,等等等等,总之总算有了一些方法,好像也慢慢有了兴趣,很开心,说这么多是想说,大家在学习的时候要注意找方法(最好有一位厉害的前辈带着!!!!入门会贼快!!!),我觉得像我一样的初学者应该还有很多,emmm,可能都要经历一个从无到有,慢慢拥有兴趣的过程叭(毕竟。。。还是感觉电子方面女生的兴趣应该不如男生多,哈哈)
希望大家可以多多点赞、评论、收藏以及加关注哦!!!谢谢大家!!!!