STM32F103RCT6V4学习历程(持续更新ing)

目录

前言

一、GPIO_LED(STM32开发的基本流程)

二、按键KEY

三、外部中断实验

四、串口通信实验

五、基本定时器



前言

为了保证学有所得,在这里记录STM32F103RCT6V4板的自学历程,包括每个模块的开发流程及其共性问题,和我参照开发手册和官方源码自己重写的代码(会有warning)持续丰满内容和更新,主要目的,是让我可以快速回顾STM32的开发工作流,并尽快上手摆脱开发手册和源代码实现自己开发。

一、GPIO_LED(STM32开发的基本流程)

GPIO头文件基本流程:
        头文件的作用是提供驱动,为xxx.c文件提供宏定义,引用库函数
        1、另定义引脚端口。2、定义GPIO时钟使能函数。3、定义GPIO控制函数。4、定义led.c文件的led初始化函数


                /1、另定义端口和引脚,如:

#define  LED0_PORT            GPIOA
#define  LED0_PIN             GPIO_PIN_8

        包括一些函数,都尽量重新定义名字,一方面是后续的程序书写更加直观更加直观,另一方面是避免直接使用库文件的函数,以免在特殊语句(如结构体中)出现语法错误
        如:
                /2、令定义函数:

#define  LED0_clk_ENABLE()    do{ __HAL_RCC_GPIOA_CLK_ENABLE(); } while(0)          // 时钟使能


        时钟使能函数在 stm32f1xx_hal_rcc.h 文件中

        直接使用库函数出错:GPIO_InitTypeDef gpio_init_type;

        //GPIO_InitTypeDef只是头文件定义的一个GPIO的结构体,不能直接用,需要定义结构体变量  没定义‘gpio_init_type’的话就会出错

另行定义函数的另一个好处就是对库函数进行包装,使用起来便捷直观而且简单
如:

/3、

#define  LED0(x)              do{x ? HAL_GPIO_WritePin(LED0_PORT,LED0_PIN,GPIO_PIN_SET):\
                                     HAL_GPIO_WritePin(LED0_PORT,LED0_PIN,GPIO_PIN_RESET);}while(0)
//控制LED开闭的函数

/4、

void led_INIT(void);


GPIO的led.c文件基本流程:

        xxx.c   文件的作用就是给main()函数提供函数,如led的初始化函数

        1、GPIO时钟使能,(直接写库函数,而不在头文件定义当然也可以但是容易出错)
        如:

    LED0_clk_ENABLE();
    LED1_clk_ENABLE();

        2、初始化GPIO口
        如:

 GPIO_InitTypeDef gpio_init_type; 
//另行定义结构体gpio_init_type,其结构体类型为GPIO_InitTypeDef,根据GPIO_InitTypeDef中的元素依此填入

另行定义结构体gpio_init_type,其结构体类型为GPIO_InitTypeDef,根据GPIO_InitTypeDef中的元素依此填入

HAL_GPIO_Init(LED0_PORT, &gpio_init_type);   //GPIO初始化


确定初始化的GPIO引脚地址

3、关灯(led初始化为熄灭状态)


main()文件的具体流程
        1、初始化HAL库
        如:

HAL_Init();

        2、设置时钟,延时
        如:

sys_stm32_clock_init(RCC_PLL_MUL9);
delay_init(72);

        3、初始化led

        4.执行函数


代码全貌:

led.h

/*定义引脚和使能*/
#ifndef  _led_h
#define  _led_h
#include ".\SYSTEM\sys\sys.h"

#define  LED0_PORT            GPIOA
#define  LED0_PIN             GPIO_PIN_8
#define  LED0_clk_ENABLE()    do{ __HAL_RCC_GPIOA_CLK_ENABLE(); } while(0)

#define  LED1_PORT            GPIOD
#define  LED1_PIN             GPIO_PIN_2
#define  LED1_clk_ENABLE()    do{ __HAL_RCC_GPIOD_CLK_ENABLE(); } while(0)

/*引脚定义完了,接下来需要定义什么时候led亮和灭*/
#define  LED0(x)              do{x ? HAL_GPIO_WritePin(LED0_PORT,LED0_PIN,GPIO_PIN_SET):\
                                     HAL_GPIO_WritePin(LED0_PORT,LED0_PIN,GPIO_PIN_RESET);}while(0)

#define  LED1(x)              do{x ? HAL_GPIO_WritePin(LED1_PORT,LED1_PIN,GPIO_PIN_SET):\
                                     HAL_GPIO_WritePin(LED1_PORT,LED1_PIN,GPIO_PIN_RESET);}while(0)
/*定义x为1时亮(GPIO_PIN_SET)否则灭*/

/*定义LED取反函数*/
////#define  LED0_Toggle()        do{HAL_GPIO_TogglePin(LED0_PORT,LED0_PIN);}while(0)
////#define  LED1_Toggle()        do{HAL_GPIO_TogglePin(LED1_PORT,LED1_PIN);}while(0)
void led_INIT(void);

#endif

led.c


#include "./BSP/led.h"
//定义LED初始化函数

void led_INIT(void)
{
    //使能GPIO口
    LED0_clk_ENABLE();
    LED1_clk_ENABLE();
    GPIO_InitTypeDef gpio_init_type; //GPIO_InitTypeDef只是头文件定义的一个GPIO的结构体,不能直接用,需要定义结构体变量
    //GPIO初始化
    gpio_init_type.Pin = LED0_PIN;  //引脚口为LED0的引脚,即8号引脚

    gpio_init_type.Mode = GPIO_MODE_OUTPUT_PP;  //模式设置为推挽输出
    gpio_init_type.Pull = GPIO_PULLUP;  //设置为上拉电阻
    gpio_init_type.Speed = GPIO_SPEED_FREQ_HIGH;  //设置为高速
    HAL_GPIO_Init(LED0_PORT, &gpio_init_type);   //GPIO初始化
    
    gpio_init_type.Pin = LED1_PIN;
    HAL_GPIO_Init(LED1_PORT, &gpio_init_type);//这里是对HAL_GPIO_Init的LED_PORT赋值,所以必须先给LED0附上,再把gpio_init_type.Pin的值改为LED1
    LED0(1);                    //关闭LED
    LED1(1);                    //关闭LED
}

 main.c

#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/delay/delay.h"
#include "./SYSTEM/usart/usart.h"
#include "./BSP/led.h"

int main(void)
{
    HAL_Init();    //初始化HAL库
    sys_stm32_clock_init(RCC_PLL_MUL9);   //设置时钟72Mhz
    delay_init(72);      //设置延时倍数为72/8=9
    led_INIT();     //初始化led
    
    while(1)
    {
        LED0(0);
        LED1(1);//初始设置LED0亮,LED1灭
        delay_ms(500);  //延时半秒
        LED0(1);
        LED1(0);
        delay_ms(500);
    }
}

二、按键KEY

头文件:
HAL_GPIO_ReadPin 函数:用于读取引脚口的电平状态信息

GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin);

定义按键被按下的状态,其余与GPIO无二。

c文件有两个函数,一个就是普通的KEY初始化和执行功能的函数,另外还有一个消除按键抖动的函数  uint8_t key_scan(uint8_t Mode)  他的作用是保证按键不会多次触发或误触发,方法是定义一个描述按键键值的变量key_upkeyval,分别判断按键是否真的被按下和哪一个按键被按下,以此来保证后续的程序执行

uint8_t key_scan(uint8_t Mode)
{
    //定义静态变量
    static uint8_t key_up = 1;    //松开标志
    uint8_t keyval = 0;  //按键按下种类判断
    if (Mode)  key_up = 1;  /*当mode=1时支持连按,相当于每循环一遍都会将key_up复位为1,
                            否则,第一下没按完,key_up为0,不会触发后续函数*/
    if (key_up && (KEY0 == 0 || KEY1 == 0 || WKUP == 1))//key_up为1,且有任意一个按键按下
    {
        delay_ms(10);//消抖
        key_up = 0;//松开前不会置位
        
        if (KEY0 == 0)  keyval = KEY0_tr;
        
        if (KEY1 == 0)  keyval = KEY1_tr;
        
        if (WKUP == 1)  keyval = WKUP_tr;
        
    }
    else if(KEY0 ==1 && KEY1 ==1 && WKUP ==0 )
    {
        key_up = 1;//没有按键按下,松开标志置位
    }
    
    return keyval;
}


代码全貌:

key.h


#ifndef _key_h
#define _key_h
#include ".\SYSTEM\sys\sys.h"
/*定义按键和LED的PORT和引脚  按键:wk_up --> PA0
                                   key1-->PA15
                                   key0-->PC5
*/
#define WKUP_GPIO_PORT                  GPIOA
#define WKUP_GPIO_PIN                   GPIO_PIN_0

#define KEY1_GPIO_PORT                  GPIOA
#define KEY1_GPIO_PIN                   GPIO_PIN_15

#define KEY0_GPIO_PORT                  GPIOC
#define KEY0_GPIO_PIN                   GPIO_PIN_5

/*定义时钟使能*/

//定义C口使能
#define KEY0_GPIO_CLK_ENABLE()          do{ __HAL_RCC_GPIOC_CLK_ENABLE(); }while(0)

//定义A口使能
#define KEY1_GPIO_CLK_ENABLE()          do{ __HAL_RCC_GPIOA_CLK_ENABLE(); }while(0)

/*定义IO口数据读取函数*/
#define KEY0                            HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_5)
#define KEY1                            HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_15)
#define WKUP                            HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)

/*定义按键状态*/
#define KEY0_tr                         1
#define KEY1_tr                         2
#define WKUP_tr                         3

void KEY_init(void);
uint8_t key_scan(uint8_t Mode);     /* 按键扫描函数 */
#endif

key.c

#include ".\BSP\KEY\key.h"
#include ".\SYSTEM\delay\delay.h"
#include ".\stm32f1xx_it.h"
#include ".\SYSTEM/usart\usart.h"

void KEY_init(void)
{
    /*定义初始化GPIO*/
    GPIO_InitTypeDef gpio_def_struct;
    /*时钟使能*/
    KEY0_GPIO_CLK_ENABLE();
    KEY1_GPIO_CLK_ENABLE();
    /*定义gpio初始特性*/
    gpio_def_struct.Pin = KEY0_GPIO_PIN;
    gpio_def_struct.Mode = GPIO_MODE_INPUT;  //上拉输入
    gpio_def_struct.Pull = GPIO_PULLUP;  //上拉电阻,KEY0是高有效输入 
    gpio_def_struct.Speed = GPIO_SPEED_FREQ_HIGH;  //高速
    HAL_GPIO_Init(KEY0_GPIO_PORT, &gpio_def_struct.Pin);  //初始化串口
    //key1也是高有效,故其他都一样
    gpio_def_struct.Pin = KEY1_GPIO_PIN;
    HAL_GPIO_Init(KEY1_GPIO_PORT, &gpio_def_struct.Pin);
    //WKUP是低有效,故要改为下拉
    gpio_def_struct.Pin = WKUP_GPIO_PIN;
    gpio_def_struct.Pull = GPIO_PULLDOWN;  //下拉电阻,WKUP是低有效输入
    HAL_GPIO_Init(WKUP_GPIO_PORT, &gpio_def_struct.Pin);
    //初始化完成
} 
//接下来要进行按键消抖

uint8_t key_scan(uint8_t Mode)
{
    //定义静态变量
    static uint8_t key_up = 1;    //松开标志
    uint8_t keyval = 0;  //按键按下种类判断
    if (Mode)  key_up = 1;  /*当mode=1时支持连按,相当于每循环一遍都会将key_up复位为1,
                            否则,第一下没按完,key_up为0,不会触发后续函数*/
    if (key_up && (KEY0 == 0 || KEY1 == 0 || WKUP == 1))//key_up为1,且有任意一个按键按下
    {
        delay_ms(10);//消抖
        key_up = 0;//松开前不会置位
        
        if (KEY0 == 0)  keyval = KEY0_tr;
        
        if (KEY1 == 0)  keyval = KEY1_tr;
        
        if (WKUP == 1)  keyval = WKUP_tr;
        
    }
    else if(KEY0 ==1 && KEY1 ==1 && WKUP ==0 )
    {
        key_up = 1;//没有按键按下,松开标志置位
    }
    
    return keyval;
}

main.c

其中的led函数用的就是上一节所编写的代码

#include ".\SYSTEM\delay\delay.h"
#include ".\SYSTEM\sys\sys.h"
#include ".\BSP\led.h"
#include ".\BSP\KEY\key.h"

int main()
{
    uint8_t key;
    
    HAL_Init();//初始化HAL库
    sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟,72Mhz */
    delay_init(72); /* 延时初始化 */
    led_INIT(); /* 初始化 LED */
    KEY_init(); /* 初始化按键 */
    LED0(0); /* 先点亮 LED0 */
    
    while(1)
    {
         key = key_scan(0); //不支持连按
         if(key != 0)
         {
            switch(key)
            {
                case KEY0_tr:           //按下key0点亮/熄灭LED0
                    LED0_Toggle();
                    break;
                case KEY1_tr:
                    LED1_Toggle();      //按下KEY1点亮/熄灭LED0
                    break;
                case WKUP_tr:
                    LED1(1);
                    LED0(0);      //按下WKUP恢复初始
                    break;
            }
            
         }
         else  delay_ms(10);
    }
}

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值