首页 > 其他分享 >《STM32MP1 M4裸机HAL库开发指南》第十二章 C语言LED灯实验

《STM32MP1 M4裸机HAL库开发指南》第十二章 C语言LED灯实验

时间:2022-11-03 13:00:30浏览次数:50  
标签:HAL int STM32MP1 unsigned 裸机 BASE GPIOF GPIOI define

第十二章C语言LED灯实验


为了加深理解汇编语言以及汇编初始化过程,第十一章我们使用汇编来控制LED0。本章节我们来学习使用C语言来控制LED0,实际的开发中我们接触最多的就是C语言了,在整个裸机开发中,基本上也都是使用C语言来完成。​

本章将分为如下几个小节:​

12.1、C语言控制LED灯简介;​

12.2、硬件设计;​

12.3、软件设计;​

12.4、编译和测试;​


12.1 C语言控制LED灯简介​

第十一章的实验是用汇编语言来控制LED0闪烁的,学习该章节的目的也就是为了加深理解汇编的初始化过程,而实际的开发中我们很少使用汇编来开发,毕竟汇编比较难,可移植性也不高。不管怎样,学习和理解汇编还是很有必要的,汇编部分主要是在芯片上电后的初始化工作,当这些工作完成后才会进入C的世界,所以,不管是用汇编语言来开发,还是使用C语言来开发,前提都是离不开汇编的启动文件startup_stm32mp15xx.s。​

本章节我们来学习使用C语言完成LED灯的控制,实际上ST官方提供的HAL库也是C语言,只是ST把具有通用性的函数封装成为接口,我们通过调用接口可以实现对应的功能,这大大提高了开发的效率以及移植性,不过这里我们先不用HAL库来开发,我们先自行编写C语言代码来实现。​

12.2 硬件设计​

硬件原理图和第十一章节一样。本章节控制的是开发板的LED0和LED1。​

《STM32MP1 M4裸机HAL库开发指南》第十二章 C语言LED灯实验_c语言


图12.2.1 LED与STM32MP157连接原理图​

可以看出,LED0 接到了PI0引脚上,当PI0输出低电平(0)的时候发光二极管 LED0 就会导通点亮,当PI0输出高电平(1)的时候发光二极管 LED0 不会导通,因此 LED0 也就不会点亮。LED1接在了PF3引脚上,同理,LED1的亮灭取决于PF3的输出电平,输出 0 就亮,输出 1 就灭。

12.3 软件设计​​

本实验配置好的实验工程已经放到了开发板光盘中:开发板光盘A-基础资料\1、程序源码\3、M4裸机驱动例程\ MP157-M4 HAL库V1.2\实验1 C语言LED灯实验。

12.3.1 创建工程​

实验的第一步都是创建工程,创建工程步骤可参考前面第六章部分。这里我们新建三个文件:启动文件startup_stm32mp15xx.s、main.c文件、main.h文件,如下图:​

《STM32MP1 M4裸机HAL库开发指南》第十二章 C语言LED灯实验_初始化_02


图12.3.1.1新建工程​

12.3.2 代码编写​

1.修改startup_stm32mp15xx.s

​我们直接拷贝STM32Cube固件包里的启动文件的代码到本工程的startup_stm32mp15xx.s文件中,文件在固件包为STM32Cube_FW_MP1_V1.2.0\Drivers\CMSIS\Device\ST\STM32MP1xx\Source\Templates\arm\startup_stm32mp15xx.s。拷贝完成后,我们修改一下地方:

IMPORT表示标号来自外部文件,本工程中没有SystemInit函数,所以我们注释掉第243行、246行、247行;本工程中只有main函数,所以224行和248行的标号__main改为main,最后修改的部分如下图所示:

《STM32MP1 M4裸机HAL库开发指南》第十二章 C语言LED灯实验_c语言_03


图12.3.2.1修改启动文件​

2. 添加main.h代码

main.h文件中主要是本工程中的GPIO相关的寄存器地址定义,这个部分其实也就和我们以前编写51单片机的代码类似,main.h的代码如下:​

#ifndef __MAIN_H
#define __MAIN_H

/*
各个外设基地址
*/
#define PERIPH_BASE (0x40000000)
#define MCU_AHB4_PERIPH_BASE (PERIPH_BASE + 0x10000000)
#define RCC_BASE (MCU_AHB4_PERIPH_BASE + 0x0000)
#define GPIOI_BASE (MCU_AHB4_PERIPH_BASE + 0xA000)
#define GPIOF_BASE (MCU_AHB4_PERIPH_BASE + 0x7000)
/*
寄存器地址
*/
#define RCC_MC_AHB4ENSETR *((volatile unsigned int *)(RCC_BASE + 0XAA8))
#define GPIOI_MODER *((volatile unsigned int *)(GPIOI_BASE + 0x0000))
#define GPIOI_OTYPER *((volatile unsigned int *)(GPIOI_BASE + 0x0004))
#define GPIOI_OSPEEDR *((volatile unsigned int *)(GPIOI_BASE + 0x0008))
#define GPIOI_PUPDR *((volatile unsigned int *)(GPIOI_BASE + 0x000C))
#define GPIOI_BSRR *((volatile unsigned int *)(GPIOI_BASE + 0x0018))

#define GPIOF_MODER *((volatile unsigned int *)(GPIOF_BASE + 0x0000))
#define GPIOF_OTYPER *((volatile unsigned int *)(GPIOF_BASE + 0x0004))
#define GPIOF_OSPEEDR *((volatile unsigned int *)(GPIOF_BASE + 0x0008))
#define GPIOF_PUPDR *((volatile unsigned int *)(GPIOF_BASE + 0x000C))
#define GPIOF_BSRR *((volatile unsigned int *)(GPIOF_BASE + 0x0018))

#define OFF 0
#define ON 1

#endif

main.h中,最后定义以下地址:​

AHB4基地址0x50000000​

GPIOI_MODER地址0x5000A000​

GPIOF_MODER地址0x50007000​

RCC基地址0x50000000​

GPIOI_OTYPER地址0x5000A004​

GPIOF_OTYPER地址0x50007004​

GPIOI基地址0x5000A000​

GPIOI_OSPEEDR 地址0x5000A008​

GPIOF_OSPEEDR地址0x50007008​

GPIOF基地址0x50007000​

GPIOI_PUPDR地址0x5000A00C​

GPIOF_PUPDR 地址0x5000700C​

RCC_MC_AHB4ENSETR地址0x50000AA8​

GPIOI_BSRR地址 0x5000A018​

GPIOF_BSRR 地址0x50007018​

表12.3.2.1本工程涉及的寄存器地址​

3. 添加main.c文件代码

main.c文件代码如下:​

#include "main.h"

/**
* @brief使能相关时钟
* @param无
* @retval无
*/
void clk_enable(void)
{
RCC_MC_AHB4ENSETR |= ((unsigned int)1 << 8); /* 使能GPIOI时钟 */
RCC_MC_AHB4ENSETR |= ((unsigned int)1 << 5); /* 使能GPIOF时钟 */
}

/**
* @brief初始化GPIO
* @param无
* @retval无
*/
void gpio_init(void)
{
/* GPIOI_0设置为输出 */
GPIOI_MODER &= ~((unsigned int)3 << (2 * 0));
GPIOI_MODER |= ((unsigned int)1 << (2 * 0));

/* GPIOI_0设置为推挽模式 */
GPIOI_OTYPER &= ~((unsigned int)1 << 0);

/* GPIOI_0设置为高速模式 */
GPIOI_OSPEEDR &= ~((unsigned int)3 << (2 * 0));
GPIOI_OSPEEDR |= ((unsigned int)2 << (2 * 0));

/* GPIOI_0设置为上拉 */
GPIOI_PUPDR &= ~((unsigned int)3 << (2 * 0));
GPIOI_PUPDR |= ((unsigned int)1 << (2 * 0));

/* GPIOF_3设置为输出 */
GPIOF_MODER &= ~((unsigned int)3 << (2 * 3));
GPIOF_MODER |= ((unsigned int)1 << (2 * 3));

/* GPIOF_3设置为推挽模式 */
GPIOF_OTYPER &= ~((unsigned int)1 << 3);

/* GPIOF_3设置为高速模式 */
GPIOF_OSPEEDR &= ~((unsigned int)3 << (2 * 3));
GPIOF_OSPEEDR |= ((unsigned int)2 << (2 * 3));

/* GPIOF_3设置为上拉 */
GPIOF_PUPDR &= ~((unsigned int)3 << (2 * 3));
GPIOF_PUPDR |= ((unsigned int)1 << (2 * 3));
}

/**
* @brief开关函数
* @param无
* @retval无
*/
void led0_switch(unsigned char state)
{
if(state == OFF)
{
GPIOI_BSRR |= ((unsigned int)1 << 0); /* GPIOI_0输出高电平 */
} else if(state == ON)
{
GPIOI_BSRR |= ((unsigned int)1 << 16); /* GPIOI_0输出低电平 */
}
}

/**
* @brief开关函数
* @param无
* @retval无
*/
void led1_switch(unsigned char state)
{
if(state == OFF)
{
GPIOF_BSRR |= ((unsigned int)1 << 3); /* GPIOF_3输出高电平 */
} else if(state == ON)
{
GPIOF_BSRR |= ((unsigned int)1 << 19); /* GPIOF_3输出低电平 */
}
}

/**
* @brief短时间延时函数
* @param要延时循环次数(空操作循环次数,模式延时)
* @retval无
*/
void delay_short(volatile unsigned int n)
{
while(n--){}
}

/**
* @brief长延时函数
* @param要延时的时间循环数
* @retval无
*/
void delay(volatile unsigned int n)
{
while(n--)
{
delay_short(0x7fff);
}
}

/**
* @brief函数
* @param无
* @retval无
*/
int main(void)
{
clk_enable(); /* 使能时钟 */
gpio_init(); /* 初始化GPIO */

while(1)
{
led0_switch(ON); /* LED0开 */
led1_switch(OFF); /* LED1关 */
delay(100); /* 延时一定时间 */
led0_switch(OFF); /* LED0关 */
led1_switch(ON); /* LED1开 */
delay(100); /* 延时一定时间 */
}
}

main.c文件的代码比较简单:​

clk_enable函数主要完成PI0和PF3的时钟开启,这里注意的是,我们没有去配置任何时钟,所以复位以后,系统默认使用内部高速时钟HSI(64MHz)来工作,此时AHB4总线的时钟为64MHz,而GIOI和GPIOF都挂在AHB4总线上,所以GPIOI和GPIOF的时钟频率也为64MHz;​

gpio_init函数PI0和PF3的初始化:设置引脚为推挽输出、上拉、高速模式;​

led0_switch函数设置PI0引脚为高或低电平;​

led1_switch函数设置PF3引脚为高或低电平;​

delay函数调用delay_short函数完成时钟延时功能,这里通过让CPU做空循环达到延时的效果;​

main函数通过调用以上函数,由while循环实现LED0和LED1交替闪烁。​

12.3.3 编译和测试​

编译工程无报错,进入仿真模式运行,最后看到LED0和LED1交替闪所,实验完成。​


标签:HAL,int,STM32MP1,unsigned,裸机,BASE,GPIOF,GPIOI,define
From: https://blog.51cto.com/u_15046463/5819415

相关文章

  • Halcon实用系列-识别二维条码
    在做项目时,之前使用的是某康的智能读码器,综合考虑成本,可通过相机拍照来读取图片的二维码,我这边用Halcon来实现。Halcon代码如下:1*创建模型2create_data_code_2d_m......
  • 【THM】Net Sec Challenge-练习
    本文相关的TryHackMe实验房间链接:https://tryhackme.com/room/netsecchallenge使用此挑战来测试你的技能掌握程度,此挑战中的所有问题都可以仅使用nmap、telnet和hydra来解......
  • Halo 主题 Redemption 首发版
    Redemption一款专注阅读、写作的Halo博客主题。主要设计思想即是专注阅读、写作,是一款极简类型的博客主题。Redemption部分设计灵感借鉴Halo博客Zozo主题,感谢各......
  • JAVA的HALF_DOWN和HALF_UP的区别?
    Java代码:publicclassBigDecimalDemo{publicstaticvoidmain(String[]args){BigDecimalbd2=BigDecimal.valueOf(11);......
  • HAL库下使用printf
    1.包含头文件#include"stdio.h"2.重定义串口intfputc(intch,FILE*f){while((USART1->SR&0X40)==0);//循环发送,直到发送完毕USART1->DR=(uint8_t)......
  • DataWhale——推荐系统实战
    推荐系统实战​​推荐系统​​推荐系统一图足矣参考:​​DataWhale​​.......
  • [I.MX6UL] 裸机点灯 C语言 GPIO的使用
    一、启动文件.global_start//全局变量_start://进入SVC模式mrsr0,cpsr//将特殊寄存器CPSR里面的数据复制到R0中bicr0,r0,#0x1f//00011111将r0......
  • STM32 HAL IIC软模拟
    IIC(Inter-IntegratedCircuit)其实是IICBus简称,所以中文应该叫集成电路总线,它是一种串行通信总线,使用多主从架构,由飞利浦公司在1980年代为了让主板、嵌入式系统或手机用以连......
  • 单片机 STM32 HAL GSM通讯 SIM800L
    /*************笔记****************1、本SIM800L模块采用huart3(串口3),然后huart1(串口1)作为调试输出。2、CudeMX配置huart3:----------------------------------------......
  • 单片机 STM32 HAL PCF8574 例子代码
    #include"extgpio.h"#include"pcf8574.h"#include"74hc595.h"/******************笔记:1、X输入Y输出2、NPN(箭头向下)高电平时导通,PNP(箭头向上)低电平时导通;3、PCF8574......