Stm32f103c8t6 基于stm32CubeMX、HAL库实现的LED流水灯,以及中断控制流水灯工作状态

目录

 

1. stm32CubeMX环境搭建

      1.1 安装Java环境(未安装Java需要安装)

      1.2 安装STM32CubeMX 

2.  新建工程,配置环境,生成KEIL代码

  2.1 新建工程

  2.2 Pinout&Configuration (端口配置)

     2.2.1 GPIO配置

     2.2.2 RCC配置

     2.2.3 SYS配置

     2.2.4 NVIC中断优先级配置

  2.3 CLK Configuration (时钟配置)

  2.4 Project Manager(工程管理)

  2.5 查看生成的代码(GPIO初始化,中断配置)

3. Keil5添加流水灯和中断代码 

3.1 任务要求

3.2 添加流水灯代码(用到的相关函数、代码思路和完整代码)

        3.2.1  程序思路

        3.2.2 输出点平配置函数

        3.2.3  读取端口状态函数

         3.2.4 延时函数

         3.2.5 代码流程图

         3.2.6  LED_Turn函数编写

  3.3  添加中断代码

 4. 实验效果

         4.1  实物效果

         4.2  仿真查看波形

5. 总结与参考


 

1. stm32CubeMX环境搭建

      1.1 安装Java环境(未安装Java需要安装)

                安装Java的链接:https://www.java.com/zh-CN/download/

                 进入下载安装就行了

      1.2 安装STM32CubeMX 

                 下载链接:https://www.st.com/en/development-tools/stm32cubemx.html

                  下载后,运行setup可执行文件:

 80c6d7e33e6949b49bb55835f3ea7018.png

617371931d4b49949b2e60c094904134.png

b7022e4f555d4a648650cd216608ebf6.png

26a393b4ca15469483437053be1d250a.png85107a6c1baf4e5c9025f83e6b750c89.png

9646d219c5814d56be7b29b43767053b.png

安装好后,进入软件主界面:

a61b07e0167a4304848fea6b39a1a37b.png

点击help->Manage embedded software packages下载对应的芯片库文件:

16d77d78cc6b4c8b8ce9658e72cda243.png

选择STM32F1->STM32Cube MCU Package for STM32F1 Series->Install

     003dc69f6aa34ed393f76dc09c5df472.png

2.  新建工程,配置环境,生成KEIL代码

        2.1 新建工程

           78fa64fcdf3847e5abf6acfb3c9f4055.png

ad39cf679207411b80209fedb7efe2bb.png

  进入配置界面:

bb51abfa9b9c428aa6512ab62e7963cb.png

       2.2 Pinout&Configuration (端口配置)

         2.2.1 GPIO配置

                    在芯片PA0处直接点击PA0, 然后选择GPIO_Output,端口变绿就说明配置成功了

388746c8cc754b15b8ea8f6d4f0fdf90.png

               同样的方法将PA0-7都配置成输出模式

               下面配置输出的速度和初始状态:

8b6889e911b141c7afbfaae2c5c9e676.png

同样配置其他PA1-7 另外7个引脚

下面将PB4配置为外部中断源

4eac35a2fa6a421abed8013a75ffcbfd.png

同样到GPIO处,选择PB4,配置PB4的中断类型:

5f955f96b65241c0abac5aa14940d720.png

     2.2.2 RCC配置

03c288cae2f84f549953c2b7f8bdbf93.png

     2.2.3 SYS配置

d8c0d46fc74d490ea4f9eb0a02f8b7d5.png

     2.2.4 NVIC中断优先级配置

ecb28b0b019e4c0cb9f3bf5c50241e07.png

2.3 CLK Configuration (时钟配置)

8482a562dd3c4041971150731eaca1dc.png

2.4 Project Manager(工程管理)

c75a3b59b77d4d8b89d058f33b5d16be.png

注意:路径不能包含中文和空格,不然生成的工程文件无法在Keil中打开

a0dea4db2d124fc39dd09a4e1372cb81.png

最后点击生成代码

8f92e241282f406b9b8b8bb5709899b8.png

  2.5 查看生成的代码(GPIO初始化,中断配置)

95d56a2a26a64890bd602bf39e9916ab.png    

3. Keil5添加流水灯和中断代码 

3.1 任务要求

         将PA0-7八个端口连接8个LED灯的阳极,LED灯阴极接地,那么端口输出高电平LED灯就亮,低电平灯就灭。加上HAL_Delay()函数进行延时,实现流水灯效果。此外,将PB4引脚用作外部中断源,当PB4为高电平时,流水灯开始工作,低电平时候流水灯不工作。

3.2 添加流水灯代码(用到的相关函数、代码思路和完整代码)

        3.2.1  程序思路

           将PA0-7轮流置为高电平,然后延时,周而复始。

           流水灯代码需要用到的几个函数:

        3.2.2 输出点平配置函数

       void HAL_GPIO_WritePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState)      

             该函数是用来配置某个GPIO端口的输出状态

             例如要将PA0设置为高电平,则如下格式:

             HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET);

       3.2.3  读取端口状态函数

              要想知道某个 IO 口的状态,你只要读这个寄存器,再看某个位的状态就可以了。使用起
来是比较简单的。库函数相关函数为:
              GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)

               如果需要读取PB4的点平状态,那么可以如下写:

              GPIO_PinState HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_4)

       3.2.4 延时函数

             void HAL_Delay(uint32_t Delay)

33e091a470174b5b9a9b2816b56a9e3c.png

             可见,这里是通过计时器写的代码,所以是非常精确的

             该函数时一个延时函数,后面添加延时的时间,单位为ms,例如延时1s,则可以写:

              HAL_Delay(1000) 

       3.2.5 代码流程图

              6f6dfb9a389446c0a0780de48eb15716.png

          3.2.6  LED_Turn函数编写

 

void LED_Turn()
{
     HAL_GPIO_WritePin(GPIOA, GPIO_PIN_All, GPIO_PIN_RESET);
	   HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET);
		 HAL_Delay(1000);
		 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_All, GPIO_PIN_RESET);
		 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1,GPIO_PIN_SET);
		 HAL_Delay(1000);
		 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_All, GPIO_PIN_RESET);
		 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2,GPIO_PIN_SET);
		 HAL_Delay(1000);
		 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_All, GPIO_PIN_RESET);
		 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3,GPIO_PIN_SET);
		 HAL_Delay(1000);
		 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_All, GPIO_PIN_RESET);
		 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4,GPIO_PIN_SET);
		 HAL_Delay(1000);
	 	 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_All, GPIO_PIN_RESET);
		 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5,GPIO_PIN_SET);
		 HAL_Delay(1000);
		 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_All, GPIO_PIN_RESET);
		 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6,GPIO_PIN_SET);
		 HAL_Delay(1000);
		 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_All, GPIO_PIN_RESET);
		 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7,GPIO_PIN_SET);
		 HAL_Delay(1000);
}

  3.3  添加中断代码

        这里我们首先讲解 STM32F1 IO 口中断的一些基础概念。STM32F1 的每个 IO 都可以作为
外部中断的中断输入口,这点也是 STM32F1 的强大之处。STM32F103 的中断控制器支持 19
个外部中断/事件请求。每个中断设有状态位,每个中断/事件都有独立的触发和屏蔽设置。
STM32F103 的 19 个外部中断为:
EXTI 线 0~15:对应外部 IO 口的输入中断。
EXTI 线 16:连接到 PVD 输出。
EXTI 线 17:连接到 RTC 闹钟事件。
EXTI 线 18:连接到 USB 唤醒事件。
EXTI 线 19:连接到以太网唤醒事件。
从上面可以看出,STM32F1 供 IO 口使用的中断线只有 16 个,但是 STM32F1 的 IO 口却
远远不止 16 个,那么 STM32F1 是怎么把 16 个中断线和 IO 口一一对应起来的呢?于是 STM32
就这样设计,GPIO 的管教 GPIOx.0~GPIOx.15(x=A,B,C,D,E,F,G,H,I)分别对应中断线 0~15。这
样每个中断线对应了最多 9 个 IO 口,以线 0 为例:它对应了 GPIOA.0、GPIOB.0、GPIOC.0、
GPIOD.0、GPIOE.0、GPIOF.0、GPIOG.0。而中断线每次只能连接到 1 个 IO 口上,这样就需要
通过配置来决定对应的中断线配置到哪个 GPIO 上了。下面我们看看 GPIO 跟中断线的映射关
17e9b17b4f8642a5996809a5c440f59f.png
     在此实验中,用到的是PB4外部中断IO口,因此,需要连接4号中断线。、
     这些初始化我们都已经在stm32cubeMX的ui界面已经配置好了,上面查看生成的代码也给出了解释。我们需要做的是编写中断服务程序。
中断服务函数的名字是
     在 HAL 库中事先有定义的。这里需要说明一下,STM32F1 的 IO 口外部中断函数只有 7 个,分别为:
                        void EXTI0_IRQHandler();
                        void EXTI1_IRQHandler();
                        void EXTI2_IRQHandler();
                        void EXTI3_IRQHandler();
                        void EXTI4_IRQHandler();
                        void EXTI9_5_IRQHandler();
                        void EXTI15_10_IRQHandler();
这和上面的中断线是对应的,我们可以直接在该函数编写中断逻辑,但是HAL库为了用户方便,提供了另一个中断通用入口函数:HAL_GPIO_EXTI_IRQHandler, 该函数内部直接调用回调函数HAL_GPIO_EXTI_Callback
查看HAL_GPIO_EXTI_IRQHandler函数定义
 
3d81a05285e840e8a7089d6a77460780.png
可见,该函数首先判断是否有中断标志,是的话进入清除了中断标志,然后进入回调函数,我们可以直接把回调函数删了,填写我们的中断逻辑,但是也可以在回调函数中写我们的中断逻辑代码。
在此实验中,我们需要做的是,当PB4触发中断后,PB4为高电平就让流水灯工作,低电平就让流水灯不工作。
编写回调函数;
 
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
  	if(GPIO_Pin==GPIO_PIN_4)
	{ 
		 if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_4)==GPIO_PIN_RESET)//ϽµÑØ
	      flag=0;
		 if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_4)==GPIO_PIN_SET) //ÉÏÉýÑØ
			 flag=1;//Á÷Ë®µÆ¹¤×÷
	}
	   
}

代码解释:GPIO_Pin是哪个端口触发的中断,因为我们是PB4,所以是第四个端口,因此首先添加判断如果是GPIO_PIN_4触发的中断,再判断电平,高电平flag置1,低电平flag置0。在主函数中,我们也需要编写逻辑,思路是判断如果flag==1,就调用流水灯函数,如果是0就直接全部灯灭就行了。

主函数逻辑:

while (1)
  {
   
   if(flag==1)
		{
		 LED_Turn();	 
		}
		if(flag==0)
		{
		 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_All, GPIO_PIN_RESET);
		}
   
  }

代码流程图:

2f85f45040104c2493689f5ff58909ba.png

 
 

 4. 实验效果

         4.1  实物效果

                      956f57d6bb914a47b088d6326d9df544.gif 

         4.2     仿真查看波形

                           仿真查看波形需要修改一下源码,直接在while1中调用流水灯程序,查看电平持续时间,仿真需要的MDK配置:

ac0a2abb1c0f40fabd543f7b39a5c405.png

修改循环中的代码:

while(1)
{
   LED_Turn();
}

 仿真查看波形:

ae78d83d0d724e478033e6f13085242c.png

5. 总结与参考

      1. 对比之前的寄存器开发流水灯、库函数开发版本,HAL库开发效率大幅度提高,只需要在stm32cubeMX的UI界面进行操作,很快的就能配置好所需内容,之前的寄存器开发需要去查找手册每个寄存器的作用,需要知道如何设寄存器才能有对应的效果,库函数开发相比寄存器开发效率提高了很多,我们不需要知道寄存器的作用,官方通过库函数封装起来了,只需要调用对应的库函数就能完成操作,相比之下开发效率更高,而且方便记忆。HAL库就逆天了,直接鼠标点击几下,不需要知道什么寄存器、什么库函数,直接就能在UI界面进行配置,然后生成代码。但是HAL库的代码逻辑还是需要自己手动去添加,HAL库生成的代码其实是和库函数是很像的,只是函数名字不一样,但是读名字也很容易发现对应函数的功能。

       2. 实物实验结果分析:通过查看视频,首先我们烧录代码后,LED灯是没有变化的,因为这时候并不知道flag的值是多少,我们没有赋值,只是定义了flag。当我们将PB4接入高电平的时候,会触发上升沿中断(PB4是拉低的,因此初始化是低电平),这时候会进入中断,设置flag=1,然后回到死循环,死循环中判别到flag=1,这时候就调用了LED_Turn(),流水灯函数,流水灯就开始工作了,当PB4从高电平中取出来,即产生了下降沿中断,这时候flag=0,然后回到了死循环,这时候会继续执行死循环中的内容,如果流水灯程序还没执行完,会将流水灯执行完后,然后停止工作,这样就通过PB4接入高电平控制流水灯工作,低电平控制流水灯不工作,但是这里有一个小问题,就是当PB4接入低电平的时候不能直接停止工作,而是需要等待到死循环中判断flag=0处才能停止,这也符合中断逻辑,中断后进入中断函数,执行完后回到主函数继续执行未执行的内容。

        3. 仿真结果分析:通过查看仿真波形,高电平开始时间为2.0s,结束时间为3.02s,那么可以得出高电平持续时间为1.2s,灯亮的时间就为1.2s,这是仿真得出来的结果,但是按照代码逻辑,我们调用的是封装的库函数,里面是通过定时器延时的,所以是准确的一秒钟,因此可以得出仿真的电平持续时间是多了0.02s的误差的,误差为2%,还是挺小的。

 PS:参考网址

STM32实现LED闪烁——基于HAL库_编程实现led灯闪烁stm32库-CSDN博客

【精选】STM32基于HAL库流水灯实验_hel库安装教程中文版-CSDN博客

 

  • 3
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
以下是使用STM32CubeIDE编写的点亮LED流水灯的代码: ```c #include "main.h" /* 定义LED灯引脚 */ #define LED_PIN GPIO_PIN_13 #define LED_PORT GPIOC /* 定义延迟函数 */ void delay(uint32_t time) { /* 获取当前系统滴答定时器的计数值 */ uint32_t tickstart = HAL_GetTick(); /* 等待指定时间 */ while((HAL_GetTick() - tickstart) < time); } int main(void) { /* 初始化HAL库 */ HAL_Init(); /* 初始化系统时钟 */ SystemClock_Config(); /* 使能GPIOC时钟 */ __HAL_RCC_GPIOC_CLK_ENABLE(); /* 配置LED引脚为推挽输出 */ GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Pin = LED_PIN; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(LED_PORT, &GPIO_InitStruct); /* 循环执行流水灯效果 */ while (1) { /* 点亮第一个LED */ HAL_GPIO_WritePin(LED_PORT, LED_PIN, GPIO_PIN_RESET); delay(100); /* 点亮第二个LED */ HAL_GPIO_WritePin(LED_PORT, LED_PIN, GPIO_PIN_SET); delay(100); /* 点亮第三个LED */ HAL_GPIO_WritePin(LED_PORT, LED_PIN, GPIO_PIN_RESET); delay(100); /* 点亮第四个LED */ HAL_GPIO_WritePin(LED_PORT, LED_PIN, GPIO_PIN_SET); delay(100); /* 点亮第五个LED */ HAL_GPIO_WritePin(LED_PORT, LED_PIN, GPIO_PIN_RESET); delay(100); /* 点亮第六个LED */ HAL_GPIO_WritePin(LED_PORT, LED_PIN, GPIO_PIN_SET); delay(100); /* 点亮第七个LED */ HAL_GPIO_WritePin(LED_PORT, LED_PIN, GPIO_PIN_RESET); delay(100); /* 点亮第八个LED */ HAL_GPIO_WritePin(LED_PORT, LED_PIN, GPIO_PIN_SET); delay(100); } } ``` 在这个代码中,我们首先定义了LED灯所连接的引脚,在main函数中初始化了GPIOC时钟,并配置LED引脚为推挽输出。然后在一个无限循环中,不断执行流水灯效果:先点亮第一个LED,等待一段时间后熄灭,然后点亮第二个LED,再等待一段时间后熄灭,以此类推,一直循环下去。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值