黄工无刷电机学习
直播中

ronga245

13年用户 590经验值
私信 关注
[问答]

如何实现基于STM32f103单片机按键控制电机正反转?

如何实现基于STM32f103单片机按键控制电机正反转?

回帖(1)

范召琳

2021-10-14 10:05:42
学了快半个月的STM32,收获颇多,很明显的感觉是32位的单片机要比8位单片机(51单片机)强的太多了,不管是性能还是功耗上和51是没法比的,而且还有许多的外设模块。stm32是ARM Cortex-M3内核的单片机,由于介绍STM32不是重点,这里我就不再赘述。
用的是板子是f103ZET6的最小系统板,用的库是32的库函数(正点原子)。
初期我主要学习了GPIO的配置、位操作、LED灯、蜂鸣器、外部中断、串口中断、定时器中断、定时器产生PWM。我准备将学习的内容结合起来做一个项目,也是对学习的总结(由于是在假期写的,没法去调试检验,语法是没有错误和警告的,如果有错误欢迎指正!)。


简述
1、通过四个按键控制两个电机的正反转,按键采用连续按有效,并且用定时器写了PWM用于降低电机转动的速度;
2、在初始化中写了LED闪烁程序和蜂鸣器滴滴响的程序,在本程序中主要用于开机初始化,如果有其他用处可以修改参数调用即可;
3、由于发现每次使用IO口、使用串口、使用定时器中断、定时器产生PWM都需要配置,所以我在其他文件夹中将j将其进行了配置,如果需要使用只需要调用函数和修改参数即可;
4、我将所有自己写的.h文件放在了HEAD.h中,所有自己写的.c文件中的函数初始化都放在HEAD.c中的HEAD_Init()函数中(除了在main.c文件中的函数),使用时在main.c文件中调用HEAD.H和HEAD_Init()进行函数初始化。这样做的目的在于将代码规范、整洁化。


IO口和模块的使用
该程序中初始化了GPIOA、B、C、D、E、F这几个模式,共用了13个io口,
其中GPIOA_6和GPIOA_7 用于TIM3 通道1和通道2输出pwm;
GPIOD_6用于蜂鸣器;
GPIOB_5 用于LED0;
GPIOE_5 用于LED1;
GPIOC_0、GPIOC_1、GPIOC_2、GPIOC_3用于电机A和B各自信号口;
GPIOF_8、GPIOF_9、GPIOF_10、GPIOF_11用于四个独立按键连接引脚口;
只初始化配置,没有使用GPIO_G、串口、定时器中断。


配置文件介绍
这是stm32f103库函数版标准工程模板的配置文件


下面这个是包含了我自己建立的文件工程

主要有GPIO_INIT、Myself_HELD、TIMER、USART还包括HARDWEAR中的关于LED和蜂鸣器的.c和.h文件,以及三个.txt文档,MSP.IO.txt罗列了最小系统板IO口的使用,READ_GPIO.txt主要写了关于GPIO配置所用到的一些接口参数,README.txt写了我配置文件的日期以及相关的注意事项。这里的三个.txt文件都是自己写的,主要是一些注意事项。
下面我将我写的一些配置文件做一个简单的介绍

1、Myself_HEAD
这个文件夹中主要包括了head.h和head.c文件



head.h
#ifndef __HEAD_H
#define __HEAD_H


#include "stm32f10x.h"                        //stm官方库
#include "stm32f10x_usart.h"        //stm官方串口库
#include "stm32f10x_rcc.h"                //stm官方时钟库
#include "stm32f10x_tim.h"                //stm官方定时器库
#include "sys.h"                                 //位操作头文件
#include "delay.h"                                //延时头文件
#include                                 //开机LED闪烁初始化头文件
#include                                 //所有GPIO初始化配置头文件  GPIO   ABCDEFG
#include                                 //开机蜂鸣器滴滴初始化头文件
#include                                 //串口初始化以及串口中断服务函数头文件   只有配置了串口1、串口2、串口3,没有配置串口4和串口5
#include                         //定时器中断初始化以及定时器中断服务函数(只写了四个通用定时器的)还包括定时器3的四路通道产生PWM初始化


void HEAD_Init(void);                        //头文件初始化声明




#endif


head.c
#include


void HEAD_Init(void)                        //初始化各个头文件的函数,直接在main.c文件中调用HEAD_Init()
{
        //GPIO_Init_x();                        //修改x选择GPIO模式  共ABCDEFG七种  在GPIO.c文件里配置
        //在哪个函数里使用GPIO就在哪个函数里调用各个模块的初始化
        //注意引脚不能重复
        GPIO_Init_A();                        //GPIO_A初始化      A_6   A_7    TIM3 通道1和通道2输出pwm
        GPIO_Init_D();                    //GPIO_D初始化      D_6   蜂鸣器
        GPIO_Init_B();                        //gpio_B初始化      B_5   LED0
        GPIO_Init_E();                        //gpio_E初始化      E_5   LED1
        GPIO_Init_C();                    //GPIO_C初始化                C_0   C_1   C_2   C_3        电机A和B各自IN口
        GPIO_Init_F();                        //GPIO_F初始化                F_8   F_9   F_10  F_11  四个独立按键连接引脚口       
       
        TIM3_PWM_Init(99,719);                //通用定时器3    在这里用于产生PWM  初始化四个通道  TIM_SetCompare2(TIM3,x);        通道2用于输出占空比最大100  产生频率1Khz
       
        USART_Init_1(115200);                //串口1初始化声明                        32 bound_1   波特率
        delay_init();                                //延时初始化
       
        LED_Init();                                        //LED初始化
        BEEP_Init();                                //蜂鸣器初始化
}


GPIO_INIT
这个文件夹中包括GPIO.h和GPIO.c文件



GPIO.h
#ifndef __GPIO_H
#define __GPIO_H


#include "stm32f10x.h"
#include "stm32f10x_rcc.h"                                //stm官方时钟库
#include "sys.h"
//需要修改gpio配置参数直接修改GPIO.C文件中的参数
void GPIO_Init_A(void);                                //GPIO_A   初始化函数声明
void GPIO_Init_B(void);                                //GPIO_B   初始化函数声明
void GPIO_Init_C(void);                                //GPIO_C   初始化函数声明
void GPIO_Init_D(void);                                //GPIO_D   初始化函数声明
void GPIO_Init_E(void);                                //GPIO_E   初始化函数声明
void GPIO_Init_F(void);                                //GPIO_F   初始化函数声明
void GPIO_Init_G(void);                                //GPIO_G   初始化函数声明




#endif


/*3种最大翻转速度:
       -2MHZ
       -10MHz
       -50MHz*/
/*(1)GPIO_Mode_AIN 模拟输入
(2)GPIO_Mode_IN_FLOATING 浮空输入
(3)GPIO_Mode_IPD 下拉输入
(4)GPIO_Mode_IPU 上拉输入
(5)GPIO_Mode_Out_OD 开漏输出
(6)GPIO_Mode_Out_PP 推挽输出
(7)GPIO_Mode_AF_OD 复用开漏输出
(8)GPIO_Mode_AF_PP 复用推挽输出
*/                         


GPIO.c
这里我将GPIO的七个模式都进行了初始化,如果有需要只需要修改相关的接口参数,然后进行函数调用就可以了。


#include


void GPIO_Init_A(void)                                                //GPIO_A
{
        GPIO_InitTypeDef GPIO_InitStructurc_A;
       
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);        //使能GPIO_A端口
       
        GPIO_InitStructurc_A.GPIO_Mode=GPIO_Mode_Out_PP;                        //GPIO_A配置                        推挽输出
        GPIO_InitStructurc_A.GPIO_Pin=GPIO_Pin_6;                                        //设置对应引脚                        输出pwm                TIM3通道1
        GPIO_InitStructurc_A.GPIO_Pin=GPIO_Pin_7;                                        //设置对应引脚                        输出pwm                TIM3通道2
        GPIO_InitStructurc_A.GPIO_Speed=GPIO_Speed_50MHz;                        //选择最大反转速度(2、10、50)
        GPIO_Init(GPIOA,&GPIO_InitStructurc_A);                                        //GPIOA初始化
       
}


void GPIO_Init_B(void)                                                //GPIO_B
{
        GPIO_InitTypeDef GPIO_InitStructurc_B;
       
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);        //使能GPIO_B端口
       
        GPIO_InitStructurc_B.GPIO_Mode=GPIO_Mode_Out_PP;                        //GPIO_B配置                                推挽输出
        GPIO_InitStructurc_B.GPIO_Pin=GPIO_Pin_5;                                        //设置对应引脚                LED_B_5
       
        GPIO_InitStructurc_B.GPIO_Speed=GPIO_Speed_50MHz;                        //选择最大反转速度(2、10、50)
        GPIO_Init(GPIOB,&GPIO_InitStructurc_B);                                        //GPIO_B初始化
        GPIO_SetBits(GPIOB,GPIO_Pin_5);                                                        //GPIO_B   引脚pin_5输出高电平   LED_B_5  引脚状态初始化LED灭
       
}


void GPIO_Init_C(void)                                                //GPIO_C
{
        GPIO_InitTypeDef GPIO_InitStructurc_C;
       
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);        //使能GPIO_C端口
       
        GPIO_InitStructurc_C.GPIO_Mode=GPIO_Mode_Out_PP;                        //GPIO_C配置                                推挽输出
        GPIO_InitStructurc_C.GPIO_Pin=GPIO_Pin_0;                                    //设置对应引脚                                电机A  IN1
        GPIO_InitStructurc_C.GPIO_Pin=GPIO_Pin_1;                                    //设置对应引脚                                电机A  IN2
        GPIO_InitStructurc_C.GPIO_Pin=GPIO_Pin_2;                                    //设置对应引脚                                电机B  IN1
        GPIO_InitStructurc_C.GPIO_Pin=GPIO_Pin_3;                                    //设置对应引脚                                电机B  IN2
        GPIO_InitStructurc_C.GPIO_Speed=GPIO_Speed_50MHz;                        //选择最大反转速度(2、10、50)
        GPIO_Init(GPIOC,&GPIO_InitStructurc_C);                                        //GPIO_C初始化
       
        GPIO_ResetBits(GPIOC,GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3);        //GPIO_C   引脚pin_0输出低电平   引脚状态初始化                电机引脚初始化低电平
       
       
}


void GPIO_Init_D(void)                                                //GPIO_D
{
        GPIO_InitTypeDef GPIO_InitStructurc_D;
       
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD,ENABLE);        //使能GPIO_D端口
       
        GPIO_InitStructurc_D.GPIO_Mode=GPIO_Mode_Out_PP;                        //GPIO_D配置                                推挽输出
        GPIO_InitStructurc_D.GPIO_Pin=GPIO_Pin_6;                                        //设置对应引脚                BEEP_F
        GPIO_InitStructurc_D.GPIO_Speed=GPIO_Speed_50MHz;                        //选择最大反转速度(2、10、50)
        GPIO_Init(GPIOD,&GPIO_InitStructurc_D);                                        //GPIO_D初始化
        GPIO_ResetBits(GPIOD,GPIO_Pin_6);                                                        //GPIO_D   引脚pin_8输出低电平   BEEP_F   引脚状态初始化蜂鸣器不响
       
}


void GPIO_Init_E(void)                                                //GPIO_E
{
        GPIO_InitTypeDef GPIO_InitStructurc_E;
       
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE,ENABLE);        //使能GPIO_E端口
       
        GPIO_InitStructurc_E.GPIO_Mode=GPIO_Mode_Out_PP;                        //GPIO_E配置                                推挽输出
        GPIO_InitStructurc_E.GPIO_Pin=GPIO_Pin_5;                                        //设置对应引脚
        GPIO_InitStructurc_E.GPIO_Speed=GPIO_Speed_50MHz;                        //选择最大反转速度(2、10、50)
        GPIO_Init(GPIOE,&GPIO_InitStructurc_E);                                        //GPIO_E初始化
        GPIO_SetBits(GPIOE,GPIO_Pin_5);                                                        //GPIO_E   引脚pin_5输出高电平  LED_E_5 引脚状态初始化
       
}




void GPIO_Init_F(void)                                                //GPIO_F
{
        GPIO_InitTypeDef GPIO_InitStructurc_F;
       
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOF,ENABLE);        //使能GPIO_F端口
       
        GPIO_InitStructurc_F.GPIO_Mode=GPIO_Mode_IPU;                            //GPIO_F配置                   输入上拉                低电平有效
        GPIO_InitStructurc_F.GPIO_Pin=GPIO_Pin_8;                                        //设置对应引脚                        按键1  控制电机A 正转
        GPIO_InitStructurc_F.GPIO_Pin=GPIO_Pin_9;                                        //设置对应引脚                        按键2  控制电机A 反转
        GPIO_InitStructurc_F.GPIO_Pin=GPIO_Pin_10;                                        //设置对应引脚                        按键3  控制电机B 正转
        GPIO_InitStructurc_F.GPIO_Pin=GPIO_Pin_11;                                        //设置对应引脚                        按键4  控制电机B 反转
        GPIO_InitStructurc_F.GPIO_Speed=GPIO_Speed_50MHz;                        //选择最大反转速度(2、10、50)
        GPIO_Init(GPIOF,&GPIO_InitStructurc_F);                                        //GPIO_F初始化
}


void GPIO_Init_G(void)                                                //GPIO_G
{
        GPIO_InitTypeDef GPIO_InitStructurc_G;
       
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOG,ENABLE);        //使能GPIO_G端口
       
        GPIO_InitStructurc_G.GPIO_Mode=GPIO_Mode_Out_PP;                        //GPIO_G配置                                推挽输出
        GPIO_InitStructurc_G.GPIO_Pin=GPIO_Pin_5;                                        //设置对应引脚
        GPIO_InitStructurc_G.GPIO_Speed=GPIO_Speed_50MHz;                        //选择最大反转速度(2、10、50)
        GPIO_Init(GPIOG,&GPIO_InitStructurc_G);                                        //GPIO_G初始化
        GPIO_SetBits(GPIOG,GPIO_Pin_5);                                                        //GPIO_G   引脚pin_5输出高电平   引脚状态初始化
}


TIMER
由于STM32f103中有8个定时器,这个里面我建立了三个文件夹,分布别是保存2个高级定时器TIM1、TIM8的ADVANCED_TIMER文件夹。保存2个基本定时器TIM6和TIM7的BASIC_TIMER文件夹。保存4个通用定时器TIM2、TIM3、TIM4、TIM5的UNIVERSAL_TIMER文件夹。
我只配置了通用定时器






UNIVERSAL_TIMER文件夹中有关于通用定时器的.h和.c文件
这里我将4个通用定时器用于中断的配置和用定时器3的4个通道输出PWM都进行了初始化,(注意:高级定时器有8通道产生pwm,基本定时器没有通道产生pwm,通用定时器有4通道产生pwm)如果有需要只需要修改相关的接口参数,然后进行函数调用就可以了。


U_Timer.h
#ifndef __U_Timer_H
#define __U_Timer_H


#include "stm32f10x.h"
#include "stm32f10x_rcc.h"                                //stm官方时钟库
#include "stm32f10x_tim.h"                                //stm官方定时器库


#include "delay.h"
#include




//定时器1和8是高级定时器,6和7是基本定时器,在U_Timer.c里初始化通用定时器


void TIM2_Int_Init(u16 arr_2,u16 psc_2);                                //通用定时器2   
void TIM3_Int_Init(u16 arr_3,u16 psc_3);                                //通用定时器3    在这里用于产生中断
void TIM4_Int_Init(u16 arr_4,u16 psc_4);                                //通用定时器4   
void TIM5_Int_Init(u16 arr_5,u16 psc_5);                                //通用定时器3   




void TIM2_IRQHandler(void);   //TIM2中断服务函数
void TIM3_IRQHandler(void);   //TIM3中断服务函数
void TIM4_IRQHandler(void);   //TIM4中断服务函数
void TIM5_IRQHandler(void);   //TIM5中断服务函数


//在主函数中初始化   
void TIM3_PWM_Init(u16 arr,u16 psc);                                        //定时器3PWM初始化                通道1、通道2、通道3、通道4
#endif


U_Timer.c
#include
//通用定时器2中断初始化
//这里时钟选择为APB1的2倍,而APB1为36M
//arr:自动重装值。
//psc:时钟预分频数
//这里使用的是定时器2!
void TIM2_Int_Init(u16 arr_2,u16 psc_2)
{
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure_2;
        NVIC_InitTypeDef NVIC_InitStructure_2;


        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //时钟使能
       
        //定时器TIM2初始化
        TIM_TimeBaseStructure_2.TIM_Period = arr_2; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值       
        TIM_TimeBaseStructure_2.TIM_Prescaler =psc_2; //设置用来作为TIMx时钟频率除数的预分频值
        TIM_TimeBaseStructure_2.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
        TIM_TimeBaseStructure_2.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
        TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure_2); //根据指定的参数初始化TIMx的时间基数单位

        TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE ); //使能指定的TIM2中断,允许更新中断


        //中断优先级NVIC设置
        NVIC_InitStructure_2.NVIC_IRQChannel = TIM2_IRQn;  //TIM2中断
        NVIC_InitStructure_2.NVIC_IRQChannelPreemptionPriority = 0;  //先占优先级0级
        NVIC_InitStructure_2.NVIC_IRQChannelSubPriority = 2;  //从优先级2级
        NVIC_InitStructure_2.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
        NVIC_Init(&NVIC_InitStructure_2);  //初始化NVIC寄存器
       
        TIM_Cmd(TIM2, ENABLE);  //使能TIMx                                         
}


//通用定时器3中断初始化
//这里时钟选择为APB1的2倍,而APB1为36M
//arr:自动重装值。
//psc:时钟预分频数
//这里使用的是定时器3!
void TIM3_Int_Init(u16 arr_3,u16 psc_3)
{
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure_3;
        NVIC_InitTypeDef NVIC_InitStructure_3;


        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能
       
        //定时器TIM3初始化
        TIM_TimeBaseStructure_3.TIM_Period = arr_3; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值       
        TIM_TimeBaseStructure_3.TIM_Prescaler =psc_3; //设置用来作为TIMx时钟频率除数的预分频值
        TIM_TimeBaseStructure_3.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
        TIM_TimeBaseStructure_3.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
        TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure_3); //根据指定的参数初始化TIMx的时间基数单位

        TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); //使能指定的TIM3中断,允许更新中断
        //中断优先级NVIC设置
        NVIC_InitStructure_3.NVIC_IRQChannel = TIM3_IRQn;  //TIM3中断
        NVIC_InitStructure_3.NVIC_IRQChannelPreemptionPriority = 0;  //先占优先级0级
        NVIC_InitStructure_3.NVIC_IRQChannelSubPriority = 3;  //从优先级3级
        NVIC_InitStructure_3.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
        NVIC_Init(&NVIC_InitStructure_3);  //初始化NVIC寄存器
       
        TIM_Cmd(TIM3, ENABLE);  //使能TIMx                                         
}


//通用定时器4中断初始化
//这里时钟选择为APB1的2倍,而APB1为36M
//arr:自动重装值。
//psc:时钟预分频数
//这里使用的是定时器3!
void TIM4_Int_Init(u16 arr_4,u16 psc_4)
{
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure_4;
        NVIC_InitTypeDef NVIC_InitStructure_4;


        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); //时钟使能
       
        //定时器TIM3初始化
        TIM_TimeBaseStructure_4.TIM_Period = arr_4; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值       
        TIM_TimeBaseStructure_4.TIM_Prescaler =psc_4; //设置用来作为TIMx时钟频率除数的预分频值
        TIM_TimeBaseStructure_4.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
        TIM_TimeBaseStructure_4.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
        TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure_4); //根据指定的参数初始化TIMx的时间基数单位

        TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE ); //使能指定的TIM4中断,允许更新中断


        //中断优先级NVIC设置
        NVIC_InitStructure_4.NVIC_IRQChannel = TIM3_IRQn;  //TIM3中断
        NVIC_InitStructure_4.NVIC_IRQChannelPreemptionPriority = 3;  //先占优先级3级
        NVIC_InitStructure_4.NVIC_IRQChannelSubPriority = 3;  //从优先级3级
        NVIC_InitStructure_4.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
        NVIC_Init(&NVIC_InitStructure_4);  //初始化NVIC寄存器
       
        TIM_Cmd(TIM4, ENABLE);  //使能TIMx                                         
}


//通用定时器5中断初始化
//这里时钟选择为APB1的2倍,而APB1为36M
//arr:自动重装值。
//psc:时钟预分频数
//这里使用的是定时器3!
void TIM5_Int_Init(u16 arr_5,u16 psc_5)
{
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure_5;
        NVIC_InitTypeDef NVIC_InitStructure_5;


        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE); //时钟使能
       
        //定时器TIM3初始化
        TIM_TimeBaseStructure_5.TIM_Period = arr_5; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值       
        TIM_TimeBaseStructure_5.TIM_Prescaler =psc_5; //设置用来作为TIMx时钟频率除数的预分频值
        TIM_TimeBaseStructure_5.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
        TIM_TimeBaseStructure_5.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
        TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure_5); //根据指定的参数初始化TIMx的时间基数单位

        TIM_ITConfig(TIM5,TIM_IT_Update,ENABLE ); //使能指定的TIM5中断,允许更新中断


        //中断优先级NVIC设置
        NVIC_InitStructure_5.NVIC_IRQChannel = TIM3_IRQn;  //TIM5中断
        NVIC_InitStructure_5.NVIC_IRQChannelPreemptionPriority = 3;  //先占优先级3级
        NVIC_InitStructure_5.NVIC_IRQChannelSubPriority = 2;  //从优先级2级
        NVIC_InitStructure_5.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
        NVIC_Init(&NVIC_InitStructure_5);  //初始化NVIC寄存器
       
        TIM_Cmd(TIM5, ENABLE);  //使能TIMx                                         
}


/*-----------------------------------------------------------------------------------------------------*/
/***********************************上一部分定时器初始化***********************************************/
/********************************下一部分定时器中断服务函数********************************************/
/*-----------------------------------------------------------------------------------------------------*/
//定时器2中断服务程序
void TIM2_IRQHandler(void)   //TIM2中断
{
        if (TIM_GetITStatus(TIM2,TIM_IT_Update)!=RESET)  //检查TIM3更新中断发生与否
                {
                TIM_ClearITPendingBit(TIM2,TIM_IT_Update);  //清除TIMx更新中断标志
                /*
                        ---------------如果使用自己定义定时器中断代码-------------
                */       
                }
}


//定时器3中断服务程序
void TIM3_IRQHandler(void)   //TIM3中断
{
        if (TIM_GetITStatus(TIM3,TIM_IT_Update)!=RESET)  //检查TIM3更新中断发生与否
                {
                TIM_ClearITPendingBit(TIM3,TIM_IT_Update);  //清除TIMx更新中断标志
                /*
                        ---------------如果使用自己定义定时器中断代码-------------
                */       
                }
}
//定时器4中断服务程序
void TIM4_IRQHandler(void)   //TIM4中断
{
        if (TIM_GetITStatus(TIM4,TIM_IT_Update)!=RESET)  //检查TIM4更新中断发生与否
                {
                TIM_ClearITPendingBit(TIM4,TIM_IT_Update);  //清除TIMx更新中断标志
                /*
                        --------------如果使用自己定义定时器中断代码-------------
                */       
                }
}
//定时器5中断服务程序
void TIM5_IRQHandler(void)   //TIM5中断
{
        if (TIM_GetITStatus(TIM5,TIM_IT_Update)!=RESET)  //检查TIM5更新中断发生与否
                {
                TIM_ClearITPendingBit(TIM5,TIM_IT_Update);  //清除TIMx更新中断标志
                /*
                        -------------如果使用自己定义定时器中断代码-------------
                */       
                }
}




//TIM3 PWM部分初始化
//PWM输出初始化
//arr:自动重装值
//psc:时钟预分频数
void TIM3_PWM_Init(u16 arr,u16 psc)
{  
       
        TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
        TIM_OCInitTypeDef  TIM_OCInitStructure;
       


        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);        //使能定时器3时钟


   //初始化TIM3
        TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
        TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
        TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
        TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
        TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
       
        //初始化TIM3 Channel2 PWM模式         
        TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //选择定时器模式:TIM脉冲宽度调制模式2
        TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
        TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
       
        TIM_OC1Init(TIM3, &TIM_OCInitStructure);  //根据T指定的参数初始化外设TIM3 OC1            PA_6
        TIM_OC2Init(TIM3, &TIM_OCInitStructure);  //根据T指定的参数初始化外设TIM3 OC2                PA_7
        TIM_OC3Init(TIM3, &TIM_OCInitStructure);  //根据T指定的参数初始化外设TIM3 OC3
        TIM_OC4Init(TIM3, &TIM_OCInitStructure);  //根据T指定的参数初始化外设TIM3 OC4
       
        TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);  //使能TIM2在CCR1上的预装载寄存器
        TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);  //使能TIM2在CCR2上的预装载寄存器
        TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable);  //使能TIM2在CCR3上的预装载寄存器
        TIM_OC4PreloadConfig(TIM3, TIM_OCPreload_Enable);  //使能TIM2在CCR4上的预装载寄存器

        TIM_Cmd(TIM3, ENABLE);  //使能TIM3
}


USART
包括USART.h和USART.c用于串口的初始化,STM32F103有5个串口,这里只配置了前三个串口。
注意:我只配置了串口,为了方便使用,主程序中虽然调用串口初始化函数,但并没有使用串口。




USART.h
#ifndef __USART_H
#define __USART_H


#include "stm32f10x.h"
#include "sys.h"
#include "delay.h"


void USART_Init_1(u32 bound_1);                                                //串口1初始化声明                        32 bound_1   波特率


void USART_Init_2(u32 bound_2);                                                //串口2初始化声明


void USART_Init_3(u32 bound_3);                                                //串口3初始化声明
//串口1用用APB2使能
//串口2、3、4、5用APB1使能


void USART1_IRQHandler(void);                                //串口中断1服务函数
void USART2_IRQHandler(void);                                //串口中断2服务函数
void USART3_IRQHandler(void);                                //串口中断3服务函数
#endif
//这里不使用串口4和串口5    固对其不进行配置
/*RXD:数据输入引脚。数据接受。
-TXD:数据发送引脚。数据发送。
串口号                RXD                    TXD
        1                PA10                  PA9
        2                        PA3                              PA2
        3                    PB11                     PB10
        4                        PC11                        PC10
        5                        PD2                                PC12*/


USART.c
#include


void USART_Init_1(u32 bound_1)                                                //串口1初始化
{
        GPIO_InitTypeDef GPIO_InitStrue_1;                                //gpio配置结构体
        USART_InitTypeDef USART_InitStrue_1;                        //usart配置结构体
        NVIC_InitTypeDef NVIC_InitStrue_1;                        //串口1中断配置结构体
       
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);                        //GPIOA配置时钟使能                       
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);                        //USART1配置时钟使能                                                用APB2使能
       
        //USART1_TX   发送       GPIOA.9初始化
        GPIO_InitStrue_1.GPIO_Mode=GPIO_Mode_AF_PP;                //GPIO_A配置                        复用推挽输出
        GPIO_InitStrue_1.GPIO_Pin=GPIO_Pin_9;                                //GPIO_A配置                        设置引脚GPIOA_9
        GPIO_InitStrue_1.GPIO_Speed=GPIO_Speed_10MHz;                //GPIO_A配置                        设置翻转速度
        GPIO_Init(GPIOA,&GPIO_InitStrue_1);                                //初始化GPIOA_9引脚
       
        //USART1_RX          接收       GPIOA.10初始化
        GPIO_InitStrue_1.GPIO_Mode=GPIO_Mode_IN_FLOATING;        //GPIO_A配置                        浮空输入
        GPIO_InitStrue_1.GPIO_Pin=GPIO_Pin_10;                        //GPIO_A配置                        设置引脚GPIOA_10
        GPIO_InitStrue_1.GPIO_Speed=GPIO_Speed_10MHz;                //GPIO_A配置                        设置翻转速度
        GPIO_Init(GPIOA,&GPIO_InitStrue_1);                                //初始化GPIOA_10引脚
       
        USART_InitStrue_1.USART_BaudRate=bound_1;                        //设置串口1的波特率
        USART_InitStrue_1.USART_HardwareFlowControl=USART_HardwareFlowControl_None;                //无硬件数据流控制
        USART_InitStrue_1.USART_Mode=USART_Mode_Tx|USART_Mode_Rx;                                                        //使能接收和发送引脚
        USART_InitStrue_1.USART_Parity=USART_Parity_No;                                                                        //无奇偶校验位
        USART_InitStrue_1.USART_StopBits=USART_StopBits_1;                                                                //一个停止位
        USART_InitStrue_1.USART_WordLength=USART_WordLength_8b;                                                        //字长为 8 位
       
        USART_Init(USART1,&USART_InitStrue_1);                        //串口1初始化
       
        USART_Cmd(USART1,ENABLE);                                                //使能串口1
       
        USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);        //开启接收中断
       
        NVIC_InitStrue_1.NVIC_IRQChannel=USART1_IRQn;                                                //串口1中断
        NVIC_InitStrue_1.NVIC_IRQChannelCmd=ENABLE;                                                        //IRQ通道使能
        NVIC_InitStrue_1.NVIC_IRQChannelPreemptionPriority=1;                                //抢占优先级1
        NVIC_InitStrue_1.NVIC_IRQChannelSubPriority=1;                                                //子优先级1
        NVIC_Init(&NVIC_InitStrue_1);
       
}


void USART_Init_2(u32 bound_2)                                                //串口2初始化
{
        GPIO_InitTypeDef GPIO_InitStrue_2;                                //gpio配置结构体
        USART_InitTypeDef USART_InitStrue_2;                        //usart配置结构体
        NVIC_InitTypeDef NVIC_InitStrue_2;                        //串口2中断配置结构体
       
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);                        //GPIOA配置时钟使能                       
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);                        //USART2配置时钟使能                        用APB1使能
       
        //USART1_TX   发送       GPIOA.2初始化
        GPIO_InitStrue_2.GPIO_Mode=GPIO_Mode_AF_PP;                //GPIO_A配置                        复用推挽输出
        GPIO_InitStrue_2.GPIO_Pin=GPIO_Pin_2;                                //GPIO_A配置                        设置引脚GPIOA_2
        GPIO_InitStrue_2.GPIO_Speed=GPIO_Speed_10MHz;                //GPIO_A配置                        设置翻转速度
        GPIO_Init(GPIOA,&GPIO_InitStrue_2);                                //初始化GPIOA_2引脚
       
        //USART1_RX          接收       GPIOA.3初始化
        GPIO_InitStrue_2.GPIO_Mode=GPIO_Mode_IN_FLOATING;        //GPIO_A配置                        浮空输入
        GPIO_InitStrue_2.GPIO_Pin=GPIO_Pin_3;                        //GPIO_A配置                        设置引脚GPIOA_3
        GPIO_InitStrue_2.GPIO_Speed=GPIO_Speed_10MHz;                //GPIO_A配置                        设置翻转速度
        GPIO_Init(GPIOA,&GPIO_InitStrue_2);                                //初始化GPIOA_3引脚
       
        USART_InitStrue_2.USART_BaudRate=bound_2;                        //设置串口2的波特率
        USART_InitStrue_2.USART_HardwareFlowControl=USART_HardwareFlowControl_None;                //无硬件数据流控制
        USART_InitStrue_2.USART_Mode=USART_Mode_Tx|USART_Mode_Rx;                                                        //使能接收和发送引脚
        USART_InitStrue_2.USART_Parity=USART_Parity_No;                                                                        //无奇偶校验位
        USART_InitStrue_2.USART_StopBits=USART_StopBits_1;                                                                //一个停止位
        USART_InitStrue_2.USART_WordLength=USART_WordLength_8b;                                                        //字长为 8 位
       
        USART_Init(USART2,&USART_InitStrue_2);                        //串口2初始化
       
        USART_Cmd(USART2,ENABLE);                                                //使能串口2
       
        USART_ITConfig(USART2,USART_IT_RXNE,ENABLE);        //开启接收中断
       
        NVIC_InitStrue_2.NVIC_IRQChannel=USART2_IRQn;                                                //串口2中断
        NVIC_InitStrue_2.NVIC_IRQChannelCmd=ENABLE;                                                        //IRQ通道使能
        NVIC_InitStrue_2.NVIC_IRQChannelPreemptionPriority=1;                                //抢占优先级1
        NVIC_InitStrue_2.NVIC_IRQChannelSubPriority=2;                                                //子优先级2
        NVIC_Init(&NVIC_InitStrue_2);
}


void USART_Init_3(u32 bound_3)                                                //串口3初始化
{
        GPIO_InitTypeDef GPIO_InitStrue_3;                                //gpio配置结构体
        USART_InitTypeDef USART_InitStrue_3;                        //usart配置结构体
        NVIC_InitTypeDef NVIC_InitStrue_3;                        //串口3中断配置结构体
       
       
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);                        //GPIOB配置时钟使能                       
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE);                        //USART3配置时钟使能                                用APB1使能
       
        //USART1_TX   发送       GPIOB.10初始化
        GPIO_InitStrue_3.GPIO_Mode=GPIO_Mode_AF_PP;                //GPIO_A配置                        复用推挽输出
        GPIO_InitStrue_3.GPIO_Pin=GPIO_Pin_10;                                //GPIO_B配置                        设置引脚GPIOB_10
        GPIO_InitStrue_3.GPIO_Speed=GPIO_Speed_10MHz;                //GPIO_B配置                        设置翻转速度
        GPIO_Init(GPIOA,&GPIO_InitStrue_3);                                //初始化GPIOA_10引脚
       
        //USART1_RX          接收       GPIOB.11初始化
        GPIO_InitStrue_3.GPIO_Mode=GPIO_Mode_IN_FLOATING;        //GPIO_B配置                        浮空输入
        GPIO_InitStrue_3.GPIO_Pin=GPIO_Pin_11;                        //GPIO_B配置                        设置引脚GPIOB_1
        GPIO_InitStrue_3.GPIO_Speed=GPIO_Speed_10MHz;                //GPIO_B配置                        设置翻转速度
        GPIO_Init(GPIOA,&GPIO_InitStrue_3);                                //初始化GPIOB_11引脚
       
        USART_InitStrue_3.USART_BaudRate=bound_3;                        //设置串口2的波特率
        USART_InitStrue_3.USART_HardwareFlowControl=USART_HardwareFlowControl_None;                //无硬件数据流控制
        USART_InitStrue_3.USART_Mode=USART_Mode_Tx|USART_Mode_Rx;                                                        //使能接收和发送引脚
        USART_InitStrue_3.USART_Parity=USART_Parity_No;                                                                        //无奇偶校验位
        USART_InitStrue_3.USART_StopBits=USART_StopBits_1;                                                                //一个停止位
        USART_InitStrue_3.USART_WordLength=USART_WordLength_8b;                                                        //字长为 8 位
       
        USART_Init(USART3,&USART_InitStrue_3);                        //串口2初始化
       
        USART_Cmd(USART3,ENABLE);                                                //使能串口2
       
        USART_ITConfig(USART3,USART_IT_RXNE,ENABLE);        //开启接收中断
       
       
        NVIC_InitStrue_3.NVIC_IRQChannel=USART3_IRQn;                                                //串口3中断
        NVIC_InitStrue_3.NVIC_IRQChannelCmd=ENABLE;                                                        //IRQ通道使能
        NVIC_InitStrue_3.NVIC_IRQChannelPreemptionPriority=1;                                //抢占优先级1
        NVIC_InitStrue_3.NVIC_IRQChannelSubPriority=3;                                                //子优先级3
        NVIC_Init(&NVIC_InitStrue_3);       


}


/********************************************************************************************************************/
/*------------------------------------------------中断服务函数------------------------------------------------------*/
/********************************************************************************************************************/
void USART1_IRQHandler(void)                                        //串口中断1服务函数
{
        u8 res_1;                                                                        //定义接收数据存储变量
         if(USART_GetITStatus(USART1,USART_IT_RXNE))                //判断是否接收到
        {
                 res_1= USART_ReceiveData(USART1);                 //将接收到的数据存储在res_1中
                 USART_SendData(USART1,res_1);                   //在上位机中输出显示接收到的数据
        }


}
void USART2_IRQHandler(void)                                        //串口中断2服务函数
{
        u8 res_2;                                                                        //定义接收数据的存储变量
         if(USART_GetITStatus(USART2,USART_IT_RXNE))                //判断是否接收到
        {
                 res_2= USART_ReceiveData(USART2);                 //将接收到的数据存储在 res_2
                 USART_SendData(USART2,res_2);                    //在上位机中输出显示接收到的数据                 
        }
}       
void USART3_IRQHandler(void)                                        //串口中断3服务函数
{
        u8 res_3;                                                                        //定义接收数据的存储变量
         if(USART_GetITStatus(USART3,USART_IT_RXNE))                //判断是否接收到
        {
                 res_3= USART_ReceiveData(USART3);                 //将接收到的数据存储在 res_3
                 USART_SendData(USART3,res_3);                    //在上位机中输出显示接收到的数据                    
        }       
}


HARDWEAR
在该文件中我写了LED闪烁和蜂鸣器1秒的滴滴响,主要用于开机启动,对于主程序没有什么影响,所以就不加以赘述。


下面对main.c中的函数和主函数进行介绍
电机控制函数
这些是连接电机驱动的信号引脚,来控制电机正反转和停止。
电机驱动可以选择L298N和TB6612
都是两路的电机驱动,可以控制两个电机,通过PWM输出引脚连接使能端,进行调速,而信号引脚控制电机正反转和停止,


在主函数里调用定时器输出pwm:


        TIM_SetCompare1(TIM3,20);                                                        //控制A电机的pwm  全速的20/100
        TIM_SetCompare2(TIM3,20);                                                        //控制B电机的pwm  全速的20/100


对于占空比进行一下简单的说明
上面的重装载值arr=99,预分频系数psc=719;(arr+1)(psc+1)
T=arr * psc /72M,结果为1ms,也就是频率为1000Hz;
PWM模式设置为TIM_OCMode_PWM2,arr=99,
arr=20——占空比为20%;


电机正反转函数:


void Motor_A_CW(void);                                        //电机A正转
void Motor_A_CCW(void);                                        //电机A反转
void Motor_B_CW(void);                                        //电机B正转
void Motor_B_CCW(void);                                        //电机B反转
void Stop_AandB(void);                                                        //电机A和B初始化停止


按键扫描函数
这里我分别写了四个按键扫描函数,在各个扫描函数中将if条件语句写了两次,用于二次判断,保证按键按下的稳定性。
还有就是当 mode_1 (这里我以按键1为例)为 0 的时候,KEY_A()函数将不支持连续按,扫描某个按键,该按键按下之后必须要松开,才能第二次触发,否则不会再响应这个按键,这样的好处就是可以防止按一次多次触发,而坏处就是在需要长按的时候比较不合适。
当 mode _1为 1 的时候,KEY_A()函数将支持连续按,如果某个按键一直按下,则会一直返回这个按键的键值,这样可以方便的实现长按检测。


u8 Key_A_CW(u8 mode_1);                                        //按键1控制电机A正转
u8 Key_A_CCW(u8 mode_2);                                //按键2控制电机A反转
u8 Key_B_CW(u8 mode_3);                                        //按键3控制电机B正转
u8 Key_B_CCW(u8 mode_4);                                //按键4控制电机B反转


main.c中的所有的程序
#include                                                                                 //包含所有的头文件和各个端口初始化


#define A_IN1 PCout(0)                                //宏定义   PCout位操作 GPIOC的输出引脚(已经在GPIO.c的 GPIO_Init_C()函数中初始化   低电平)   
#define A_IN2 PCout(1)
#define B_IN1 PCout(2)
#define B_IN2 PCout(3)


#define KEY_A PFin(8)                                //宏定义   PFin位操作 检测GPIOF的输入引脚(已经在GPIO.c的 GPIO_Init_F()函数中初始化)   
#define KEY_B PFin(9)
#define KEY_C PFin(10)
#define KEY_D PFin(11)


#define KEY1_PRES         1                                //KEY1按下
#define KEY2_PRES        2                                //KEY2按下
#define KEY3_PRES        3                                //KEY3按下
#define KEY4_PRES        4                                //KEY4按下
/****************函数声明******************/
void Motor_A_CW(void);                                        //电机A正转
void Motor_A_CCW(void);                                        //电机A反转
void Motor_B_CW(void);                                        //电机B正转
void Motor_B_CCW(void);                                        //电机B反转
void Stop_AandB(void);                                                        //电机A和B初始化停止


u8 Key_A_CW(u8 mode_1);                                        //按键1控制电机A正转
u8 Key_A_CCW(u8 mode_2);                                //按键2控制电机A反转
u8 Key_B_CW(u8 mode_3);                                        //按键3控制电机B正转
u8 Key_B_CCW(u8 mode_4);                                //按键4控制电机B反转


/******************函数********************/
void Motor_A_CW()                                                //电机A正转
{
        A_IN1=1;                                                        //电机A  信号引脚1高电平                                               
        A_IN2=0;                                                        //电机A  信号引脚2低电平
}       
void Motor_A_CCW()                                                //电机A反转
{
        A_IN1=0;                                                        //电机A  信号引脚1低电平                                               
        A_IN2=1;                                                        //电机A  信号引脚2高电平               
}
void Motor_B_CW()                                                //电机B正转
{
        B_IN1=1;                                                        //电机B  信号引脚1高电平       
        B_IN2=0;                                                        //电机B  信号引脚2低电平               
}
void Motor_B_CCW()                                                //电机B反转
{
        B_IN1=0;                                                        //电机B  信号引脚1低电平       
        B_IN2=1;                                                        //电机B  信号引脚2高电平       
}
void Stop_AandB()                                                        //电机A和B初始化停止
{
        A_IN1=0;                                                        //电机A  信号引脚1低电平                                               
        A_IN2=0;                                                        //电机A  信号引脚2低电平
        B_IN1=0;                                                        //电机B  信号引脚1低电平                                               
        B_IN2=0;                                                        //电机B  信号引脚2低电平
}




u8 Key_A_CW(u8 mode_1)                                        //按键扫描函数        按键1控制电机A正转
{
        static u8 key_up_1=1;                                //按键按松开标志
        if(mode_1)key_up_1=1;                                 //mode=1  支持连按
        if(key_up_1&&KEY_A==0)                                //KEY_A==0端低电平  上拉输入低电平有效
        {                                                                                                       
                delay_us(10);                                        //延时
                if(key_up_1&&KEY_A==0)                        //二次判断
                {
                        delay_ms(10);                                //去抖动
                        key_up_1=0;                                        //标志位清零
                        if(KEY_A==0)
                                return KEY1_PRES;                //如果按下返回标志位
                }
        }
        else if(KEY_A==1)
                 key_up_1=1;                                        //没有按键按下
        return 0;                                                        // 无按键按下
       
}
u8 Key_A_CCW(u8 mode_2)                                        //按键扫描函数        按键2控制电机A反转
{
        static u8 key_up_2=1;                                //按键按松开标志
        if(mode_2)key_up_2=1;                                 //mode=1  支持连按
        if(key_up_2&&KEY_A==0)                                //KEY_B==0端低电平  上拉输入低电平有效
        {                                                                                                       
                delay_us(10);                                        //延时
                if(key_up_2&&KEY_A==0)                        //二次判断
                {
                        delay_ms(10);                                //去抖动
                        key_up_2=0;                                        //标志位清零
                        if(KEY_B==0)
                                return KEY2_PRES;                //如果按下返回标志位
                }
        }
        else if(KEY_B==1)
                 key_up_2=1;                                        //没有按键按下
        return 0;                                                        // 无按键按下
}


u8 Key_B_CW(u8 mode_3)                                        //按键扫描函数        按键3控制电机B正转
{
        static u8 key_up_3=1;                                //按键按松开标志
        if(mode_3)key_up_3=1;                                 //mode=1  支持连按
        if(key_up_3&&KEY_C==0)                                //KEY_C==0端低电平  上拉输入低电平有效
        {                                                                                                       
                delay_us(10);                                        //延时
                if(key_up_3&&KEY_A==0)                        //二次判断
                {
                        delay_ms(10);                                //去抖动
                        key_up_3=0;                                        //标志位清零
                        if(KEY_C==0)
                                return KEY3_PRES;                //如果按下返回标志位
                }
        }
        else if(KEY_C==1)
                 key_up_3=1;                                        //没有按键按下
        return 0;                                                        // 无按键按下
}
u8 Key_B_CCW(u8 mode_4)                                        //按键扫描函数        按键4控制电机B反转
{
        static u8 key_up_4=1;                                //按键按松开标志
        if(mode_4)key_up_4=1;                                 //mode=1  支持连按
        if(key_up_4&&KEY_D==0)                                //KEY_D==0端低电平  上拉输入低电平有效
        {                                                                                                       
                delay_us(10);                                        //延时
                if(key_up_4&&KEY_D==0)                        //二次判断
                {
                        delay_ms(10);                                //去抖动
                        key_up_4=0;                                        //标志位清零
                        if(KEY_D==0)
                                return KEY4_PRES;                //如果按下返回标志位
                }
        }
        else if(KEY_D==1)
                 key_up_4=1;                                        //没有按键按下
        return 0;                                                        // 无按键按下
}


/****************主函数********************/
int main(void)
{
        //NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);                //中断优先级分组               
    HEAD_Init();                                                                                        //all初始化函数
        Stop_AandB();                                                                                //电机A和B初始化停止
               
        TIM_SetCompare1(TIM3,20);                                                        //控制A电机的pwm  全速的20/100
        TIM_SetCompare2(TIM3,20);                                                        //控制B电机的pwm  全速的20/100
        while(1)
        {
                Key_A_CW(1);                                                                         //得到键值
                Key_A_CCW(1);                                                                         //得到键值
                Key_B_CW(1);                                                                         //得到键值
                Key_B_CCW(1);                                                                         //得到键值
               
                if(KEY1_PRES==1)                                                                 //判断  标志位是否为1  如果是则执行电机转动程序
                {
                        Motor_A_CW();                                               
                }
                else                                                                                         //如果不是则延时一会,重新循环检测
                        delay_ms(10);
                if(KEY2_PRES==1)                                                                   //判断  标志位是否为1  如果是则执行电机转动程序
                {
                        Motor_A_CCW();
                }
                else                                                                                         //如果不是则延时一会,重新循环检测
                        delay_ms(10);
                if(KEY3_PRES==1)                                                                 //判断  标志位是否为1  如果是则执行电机转动程序
                {
                        Motor_B_CW();
                }else                                                                                         //如果不是则延时一会,重新循环检测
                        delay_ms(10);
                if(KEY4_PRES==1)                                                                 //判断  标志位是否为1  如果是则执行电机转动程序
                {
                        Motor_B_CCW();
                }
                else                                                                                         //如果不是则延时一会,重新循环检测
                        delay_ms(10);
        }
}


/*注意使用串口中断需要现在主函数里进行中断优先级分组  
形式为: NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);   共5组  0、1、2、3、4、*/


由于没有使用中断,所有我把中断优先级分组给注释掉了


总结
程序中有详细的注释,如果想具体的了解可以详细的去看。之所以将GPIO和串口、定时器配置好,是因为我可以吧配置好的当做一个工程模板,下次使用复制一下可以直接取用,根据具体要求,修改修改接口参数就可以了,这样可以大大的节约基础配置的时间。这是我看智能车上逐飞英飞凌的库里就是这样写的,有很大的借鉴之处。
举报

更多回帖

发帖
×
20
完善资料,
赚取积分