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

[复制链接]
1894|45
 楼主| wangtaohui 发表于 2023-11-23 23:27 | 显示全部楼层
2、创建STM32工程
2.1、工程命名
94790655f6f4e5ff8b.png
 楼主| wangtaohui 发表于 2023-11-23 23:27 | 显示全部楼层
2.2、选择芯片。注意Device一定要选择“Software Packs”,然后搜索STM32F401,选择本次使用的芯片STM32F401VEHx。如果搜索不到则说明此芯片支持包没有安装,需要安装芯片支持包。
85780655f6f5d792b6.png
 楼主| wangtaohui 发表于 2023-11-23 23:27 | 显示全部楼层
2.3、如果上一步中找不到对应的芯片支持包,则需要安装支持包
13511655f6f7ced942.png
 楼主| wangtaohui 发表于 2023-11-23 23:28 | 显示全部楼层
2.4、支持包下载界面如下图所示,左侧搜索到要开发的芯片,右侧是相关支持包。可以直接点击Install。如果下载失败,则下方的信息框中会给出提示和下载地址。可以将下载地址复制出来使用下载工具进行下载(如迅雷等),如果还无法下载,请在可访问Google的环境下进行下载。下载好的支持包可以点击File --> Import进行导入。
48021655f6f8a4e7a7.png
 楼主| wangtaohui 发表于 2023-11-23 23:28 | 显示全部楼层
2.5、芯片支持包导入后,Manager Run-Time Environment会出现如下界面,此处CORE和Startup为必选选项。
25001655f6f9643dd0.png
 楼主| wangtaohui 发表于 2023-11-23 23:28 | 显示全部楼层
2.6、仿照上一篇文章中51单片机GPIO开发那样建立相应分组和文件夹
1432655f6fa3df27b.png
 楼主| wangtaohui 发表于 2023-11-23 23:28 | 显示全部楼层
 楼主| wangtaohui 发表于 2023-11-23 23:28 | 显示全部楼层
 楼主| wangtaohui 发表于 2023-11-23 23:29 | 显示全部楼层
 楼主| wangtaohui 发表于 2023-11-23 23:29 | 显示全部楼层
 楼主| 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分组。
 楼主| wangtaohui 发表于 2023-11-23 23:29 | 显示全部楼层
3、GPIO驱动程序
3.1、LED驱动

led.h
  1. #ifndef _LED_H_
  2. #define _LED_H_
  3.         void led_init();
  4.         void led_on(unsigned char site);
  5.         void led_off(unsigned char site);
  6.         char get_led_status(unsigned char site);
  7.         void led_operate(unsigned char site,unsigned char on_off);
  8. #endif
 楼主| wangtaohui 发表于 2023-11-23 23:29 | 显示全部楼层
led.c
  1. #include "led.h"

  2. #define GPIOD_MODER (*(volatile unsigned long *)0x40020C00)
  3. #define GPIOD_OTYPER (*(volatile unsigned long *)0x40020C04)
  4. #define GPIOD_PUPDR (*(volatile unsigned long *)0x40020C0C)
  5. #define GPIOD_IDR (*(volatile unsigned long *)0x40020C10)
  6. #define GPIOD_ODR (*(volatile unsigned long *)0x40020C14)
  7. #define RCC_AHB1ENR (*(volatile unsigned long *)0x40023830)

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

  17. void led_on(unsigned char site){
  18.         led_set_init();
  19.         switch(site){
  20.                         case 0:
  21.                                 GPIOD_ODR &= ~(0x01); //PD0置0
  22.                                 break;
  23.                         case 1:
  24.                                 GPIOD_ODR &= ~(0x01<<1); //PD1置0
  25.                                 break;
  26.                         case 2:
  27.                                 GPIOD_ODR &= ~(0x01<<2); //PD2置0
  28.                                 break;
  29.                         case 3:
  30.                                 GPIOD_ODR &= ~(0x01<<3); //PD3置0
  31.                                 break;
  32.                         default:
  33.                                 break;
  34.         }
  35. }

  36. void led_off(unsigned char site){
  37.         led_set_init();
  38.         switch(site){
  39.                         case 0:
  40.                                 GPIOD_ODR |= (0x01);         //PD0置1
  41.                                 break;
  42.                         case 1:
  43.                                 GPIOD_ODR |= (0x01<<1); //PD1置1
  44.                                 break;
  45.                         case 2:
  46.                                 GPIOD_ODR |= (0x01<<2); //PD2置1
  47.                                 break;
  48.                         case 3:
  49.                                 GPIOD_ODR |= (0x01<<3); //PD3置1
  50.                                 break;
  51.                         default:
  52.                                 break;
  53.         }
  54. }

  55. char get_led_status(unsigned char site){
  56.                 switch(site){
  57.                         case 0:
  58.                                 return (GPIOD_IDR >> 0) & (0x01);
  59.                         case 1:
  60.                                 return (GPIOD_IDR >> 1) & (0x01);
  61.                         case 2:
  62.                                 return (GPIOD_IDR >> 2) & (0x01);
  63.                         case 3:
  64.                                 return (GPIOD_IDR >> 3) & (0x01);
  65.                         default:
  66.                                 return -1;
  67.         }
  68. }
  69. //on_off 0:开灯 1:关灯
  70. void led_operate(unsigned char site,unsigned char on_off){
  71.         if(on_off == 0){
  72.                 led_on(site);
  73.         }else if(on_off == 1){
  74.                 led_off(site);
  75.         }
  76. }
 楼主| wangtaohui 发表于 2023-11-23 23:30 | 显示全部楼层
3.2、Key驱动

key.h
  1. #ifndef _KEY_H_
  2. #define _KEY_H_
  3.         char scan_keyboard();
  4. #endif
 楼主| wangtaohui 发表于 2023-11-23 23:30 | 显示全部楼层
key.c
  1. #include "delay.h"
  2. #include "key.h"

  3. #define GPIOA_MODER (*(volatile unsigned long *)0x40020000)
  4. #define GPIOA_OTYPER (*(volatile unsigned long *)0x40020004)
  5. #define GPIOA_PUPDR (*(volatile unsigned long *)0x4002000C)
  6. #define GPIOA_IDR (*(volatile unsigned long *)0x40020010)
  7. #define GPIOA_ODR (*(volatile unsigned long *)0x40020014)
  8. #define RCC_AHB1ENR (*(volatile unsigned long *)0x40023830)

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

  18. char scan_keyboard(){ //返回当前操作过的按键位置
  19.         key_get_init();
  20.         char site = -1;
  21.         if(GET_GPIOA_IDR(0) == 0){
  22.                 delayms(10);
  23.                 if(GET_GPIOA_IDR(0) == 0){
  24.                         while(GET_GPIOA_IDR(0)==0);
  25.                         site = 0;
  26.                 }
  27.         }else if(GET_GPIOA_IDR(1) == 0){
  28.                 delayms(10);
  29.                 if( GET_GPIOA_IDR(1) == 0){
  30.                         while(GET_GPIOA_IDR(1) == 0);
  31.                         site = 1;
  32.                 }
  33.         }else if(GET_GPIOA_IDR(2) == 0){
  34.                 delayms(10);
  35.                 if( GET_GPIOA_IDR(2) == 0){
  36.                         while(GET_GPIOA_IDR(2) == 0);
  37.                         site = 2;
  38.                 }
  39.         }else if(GET_GPIOA_IDR(3) == 0){
  40.                 delayms(10);
  41.                 if( GET_GPIOA_IDR(3) == 0){
  42.                         while(GET_GPIOA_IDR(3) == 0);
  43.                         site = 3;
  44.                 }
  45.         }else if(GET_GPIOA_IDR(4) == 0){
  46.                 delayms(10);
  47.                 if( GET_GPIOA_IDR(4) == 0){
  48.                         while(GET_GPIOA_IDR(4) == 0);
  49.                         site = 4;
  50.                 }
  51.         }else if(GET_GPIOA_IDR(5) == 0){
  52.                 delayms(10);
  53.                 if( GET_GPIOA_IDR(5) == 0){
  54.                         while(GET_GPIOA_IDR(5) == 0);
  55.                         site = 5;
  56.                 }
  57.         }
  58.         return site;
  59. }
 楼主| wangtaohui 发表于 2023-11-23 23:30 | 显示全部楼层
delay.h
  1. #ifndef _DELAY_H_
  2. #define _DELAY_H_
  3.         void delayms(unsigned int xms);
  4. #endif
 楼主| wangtaohui 发表于 2023-11-23 23:31 | 显示全部楼层
delay.h
  1. #ifndef _DELAY_H_
  2. #define _DELAY_H_
  3.         void delayms(unsigned int xms);
  4. #endif
 楼主| wangtaohui 发表于 2023-11-23 23:31 | 显示全部楼层
delay.c
  1. #include "delay.h"

  2. void delayms(unsigned int xms){        //毫秒级延时函数
  3.         unsigned int i,j;
  4.         for(i=xms;i>0;i--){
  5.                 for(j=1500;j>0;j--);
  6.         }
  7. }
 楼主| wangtaohui 发表于 2023-11-23 23:31 | 显示全部楼层
3.3、蜂鸣器驱动

buzzer.h


  1. #ifndef _BUZZER_H_
  2. #define _BUZZER_H_
  3.         void buzzer_open();
  4.         void buzzer_off();
  5. #endif
 楼主| wangtaohui 发表于 2023-11-23 23:32 | 显示全部楼层
buzzer.c
  1. #include "buzzer.h"

  2. #define GPIOB_MODER (*(volatile unsigned long *)0x40020400)
  3. #define GPIOB_OTYPER (*(volatile unsigned long *)0x40020404)
  4. #define GPIOB_PUPDR (*(volatile unsigned long *)0x4002040C)
  5. #define GPIOB_IDR (*(volatile unsigned long *)0x40020410)
  6. #define GPIOB_ODR (*(volatile unsigned long *)0x40020414)
  7. #define RCC_AHB1ENR (*(volatile unsigned long *)0x40023830)

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

  19. void buzzer_open(){
  20.         buzzer_set_init();
  21.         GPIOB_ODR |= (0x01);         //PB0置1
  22. }

  23. void buzzer_off(){
  24.         buzzer_set_init();
  25.         GPIOB_ODR &= ~(0x01); //PB0置0
  26. }
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 在线客服 返回列表 返回顶部