打印
[STM32F4]

从51到ARM裸机开发实验(004)STM32F401VE GPIO实验

[复制链接]
楼主: wangtaohui
手机看帖
扫描二维码
随时随地手机跟帖
21
wangtaohui|  楼主 | 2023-11-23 23:27 | 只看该作者 |只看大图 回帖奖励 |倒序浏览
2、创建STM32工程
2.1、工程命名

使用特权

评论回复
22
wangtaohui|  楼主 | 2023-11-23 23:27 | 只看该作者
2.2、选择芯片。注意Device一定要选择“Software Packs”,然后搜索STM32F401,选择本次使用的芯片STM32F401VEHx。如果搜索不到则说明此芯片支持包没有安装,需要安装芯片支持包。

使用特权

评论回复
23
wangtaohui|  楼主 | 2023-11-23 23:27 | 只看该作者
2.3、如果上一步中找不到对应的芯片支持包,则需要安装支持包

使用特权

评论回复
24
wangtaohui|  楼主 | 2023-11-23 23:28 | 只看该作者
2.4、支持包下载界面如下图所示,左侧搜索到要开发的芯片,右侧是相关支持包。可以直接点击Install。如果下载失败,则下方的信息框中会给出提示和下载地址。可以将下载地址复制出来使用下载工具进行下载(如迅雷等),如果还无法下载,请在可访问Google的环境下进行下载。下载好的支持包可以点击File --> Import进行导入。

使用特权

评论回复
25
wangtaohui|  楼主 | 2023-11-23 23:28 | 只看该作者
2.5、芯片支持包导入后,Manager Run-Time Environment会出现如下界面,此处CORE和Startup为必选选项。

使用特权

评论回复
26
wangtaohui|  楼主 | 2023-11-23 23:28 | 只看该作者
2.6、仿照上一篇文章中51单片机GPIO开发那样建立相应分组和文件夹

使用特权

评论回复
27
wangtaohui|  楼主 | 2023-11-23 23:28 | 只看该作者

使用特权

评论回复
28
wangtaohui|  楼主 | 2023-11-23 23:28 | 只看该作者

使用特权

评论回复
29
wangtaohui|  楼主 | 2023-11-23 23:29 | 只看该作者

使用特权

评论回复
30
wangtaohui|  楼主 | 2023-11-23 23:29 | 只看该作者

使用特权

评论回复
31
wangtaohui|  楼主 | 2023-11-23 23:29 | 只看该作者
  2.7、创建完分组和文件夹并完成路径配置后,创建以下文件:

Keil5_STM32F401VE_GPIO_Project\DRIVER\include文件夹下创建:buzzer.h、delay.h、key.h、led.h。
Keil5_STM32F401VE_GPIO_Project\DRIVER\source文件夹下创建:buzzer.c、delay.c、key.c、led.c。并添加到工程的DRIVER分组。
Keil5_STM32F401VE_GPIO_Project\APP文件夹下创建:application.c。并添加到工程的APP分组。

使用特权

评论回复
32
wangtaohui|  楼主 | 2023-11-23 23:29 | 只看该作者
3、GPIO驱动程序
3.1、LED驱动

led.h
#ifndef _LED_H_
#define _LED_H_
        void led_init();
        void led_on(unsigned char site);
        void led_off(unsigned char site);
        char get_led_status(unsigned char site);
        void led_operate(unsigned char site,unsigned char on_off);
#endif

使用特权

评论回复
33
wangtaohui|  楼主 | 2023-11-23 23:29 | 只看该作者
led.c
#include "led.h"

#define GPIOD_MODER (*(volatile unsigned long *)0x40020C00)
#define GPIOD_OTYPER (*(volatile unsigned long *)0x40020C04)
#define GPIOD_PUPDR (*(volatile unsigned long *)0x40020C0C)
#define GPIOD_IDR (*(volatile unsigned long *)0x40020C10)
#define GPIOD_ODR (*(volatile unsigned long *)0x40020C14)
#define RCC_AHB1ENR (*(volatile unsigned long *)0x40023830)

//LED状态输出初始化
void led_set_init(){
        //1、使能GPIOD时钟
        RCC_AHB1ENR |= (0x01<<3);
        //2、后八位置为 01010101 PD0~PD3通用输出
        GPIOD_MODER = (GPIOD_MODER|0x000000ff)&0xffffff55;
        //3、PD0~PD3设为推挽输出
        GPIOD_OTYPER = GPIOD_OTYPER & 0xfffffff0;
}

void led_on(unsigned char site){
        led_set_init();
        switch(site){
                        case 0:
                                GPIOD_ODR &= ~(0x01); //PD0置0
                                break;
                        case 1:
                                GPIOD_ODR &= ~(0x01<<1); //PD1置0
                                break;
                        case 2:
                                GPIOD_ODR &= ~(0x01<<2); //PD2置0
                                break;
                        case 3:
                                GPIOD_ODR &= ~(0x01<<3); //PD3置0
                                break;
                        default:
                                break;
        }
}

void led_off(unsigned char site){
        led_set_init();
        switch(site){
                        case 0:
                                GPIOD_ODR |= (0x01);         //PD0置1
                                break;
                        case 1:
                                GPIOD_ODR |= (0x01<<1); //PD1置1
                                break;
                        case 2:
                                GPIOD_ODR |= (0x01<<2); //PD2置1
                                break;
                        case 3:
                                GPIOD_ODR |= (0x01<<3); //PD3置1
                                break;
                        default:
                                break;
        }
}

char get_led_status(unsigned char site){
                switch(site){
                        case 0:
                                return (GPIOD_IDR >> 0) & (0x01);
                        case 1:
                                return (GPIOD_IDR >> 1) & (0x01);
                        case 2:
                                return (GPIOD_IDR >> 2) & (0x01);
                        case 3:
                                return (GPIOD_IDR >> 3) & (0x01);
                        default:
                                return -1;
        }
}
//on_off 0:开灯 1:关灯
void led_operate(unsigned char site,unsigned char on_off){
        if(on_off == 0){
                led_on(site);
        }else if(on_off == 1){
                led_off(site);
        }
}

使用特权

评论回复
34
wangtaohui|  楼主 | 2023-11-23 23:30 | 只看该作者
3.2、Key驱动

key.h
#ifndef _KEY_H_
#define _KEY_H_
        char scan_keyboard();
#endif

使用特权

评论回复
35
wangtaohui|  楼主 | 2023-11-23 23:30 | 只看该作者
key.c
#include "delay.h"
#include "key.h"

#define GPIOA_MODER (*(volatile unsigned long *)0x40020000)
#define GPIOA_OTYPER (*(volatile unsigned long *)0x40020004)
#define GPIOA_PUPDR (*(volatile unsigned long *)0x4002000C)
#define GPIOA_IDR (*(volatile unsigned long *)0x40020010)
#define GPIOA_ODR (*(volatile unsigned long *)0x40020014)
#define RCC_AHB1ENR (*(volatile unsigned long *)0x40023830)

#define GET_GPIOA_IDR(x) ((GPIOA_IDR >> x) & (0x01))
       
//Key状态输入初始化
void key_get_init(){
        //1、使能GPIOA时钟
        RCC_AHB1ENR |= 0x01;
        //2、后12位置为 0000 0000 0000 PA0~PA5输入模式
        GPIOA_MODER = (GPIOA_MODER&0xfffff000);
}

char scan_keyboard(){ //返回当前操作过的按键位置
        key_get_init();
        char site = -1;
        if(GET_GPIOA_IDR(0) == 0){
                delayms(10);
                if(GET_GPIOA_IDR(0) == 0){
                        while(GET_GPIOA_IDR(0)==0);
                        site = 0;
                }
        }else if(GET_GPIOA_IDR(1) == 0){
                delayms(10);
                if( GET_GPIOA_IDR(1) == 0){
                        while(GET_GPIOA_IDR(1) == 0);
                        site = 1;
                }
        }else if(GET_GPIOA_IDR(2) == 0){
                delayms(10);
                if( GET_GPIOA_IDR(2) == 0){
                        while(GET_GPIOA_IDR(2) == 0);
                        site = 2;
                }
        }else if(GET_GPIOA_IDR(3) == 0){
                delayms(10);
                if( GET_GPIOA_IDR(3) == 0){
                        while(GET_GPIOA_IDR(3) == 0);
                        site = 3;
                }
        }else if(GET_GPIOA_IDR(4) == 0){
                delayms(10);
                if( GET_GPIOA_IDR(4) == 0){
                        while(GET_GPIOA_IDR(4) == 0);
                        site = 4;
                }
        }else if(GET_GPIOA_IDR(5) == 0){
                delayms(10);
                if( GET_GPIOA_IDR(5) == 0){
                        while(GET_GPIOA_IDR(5) == 0);
                        site = 5;
                }
        }
        return site;
}

使用特权

评论回复
36
wangtaohui|  楼主 | 2023-11-23 23:30 | 只看该作者
delay.h
#ifndef _DELAY_H_
#define _DELAY_H_
        void delayms(unsigned int xms);
#endif

使用特权

评论回复
37
wangtaohui|  楼主 | 2023-11-23 23:31 | 只看该作者
delay.h
#ifndef _DELAY_H_
#define _DELAY_H_
        void delayms(unsigned int xms);
#endif

使用特权

评论回复
38
wangtaohui|  楼主 | 2023-11-23 23:31 | 只看该作者
delay.c
#include "delay.h"

void delayms(unsigned int xms){        //毫秒级延时函数
        unsigned int i,j;
        for(i=xms;i>0;i--){
                for(j=1500;j>0;j--);
        }
}

使用特权

评论回复
39
wangtaohui|  楼主 | 2023-11-23 23:31 | 只看该作者
3.3、蜂鸣器驱动

buzzer.h


#ifndef _BUZZER_H_
#define _BUZZER_H_
        void buzzer_open();
        void buzzer_off();
#endif

使用特权

评论回复
40
wangtaohui|  楼主 | 2023-11-23 23:32 | 只看该作者
buzzer.c
#include "buzzer.h"

#define GPIOB_MODER (*(volatile unsigned long *)0x40020400)
#define GPIOB_OTYPER (*(volatile unsigned long *)0x40020404)
#define GPIOB_PUPDR (*(volatile unsigned long *)0x4002040C)
#define GPIOB_IDR (*(volatile unsigned long *)0x40020410)
#define GPIOB_ODR (*(volatile unsigned long *)0x40020414)
#define RCC_AHB1ENR (*(volatile unsigned long *)0x40023830)

//LED状态输出初始化
void buzzer_set_init(){
        //1、使能GPIOB时钟
        RCC_AHB1ENR |= (0x01<<1);
        //2、后2位置为 01 PB0通用输出
        GPIOB_MODER = (GPIOB_MODER|0x00000003)&0xfffffff1;
        //3、PB0设为推挽输出
        GPIOB_OTYPER = GPIOB_OTYPER | 0xfffffffe;
        //4、后2位置为 01 PB0使用上拉
        GPIOB_PUPDR = (GPIOB_PUPDR|0x00000003)&0xfffffff1;
}

void buzzer_open(){
        buzzer_set_init();
        GPIOB_ODR |= (0x01);         //PB0置1
}

void buzzer_off(){
        buzzer_set_init();
        GPIOB_ODR &= ~(0x01); //PB0置0
}

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则