多学多练

  • 一、题目描述
  • 二、设计思路
  • 三、寄存器实现
  • 01 时钟配置
  • 02 模式设置
  • 03 代码编写
  • 04 创建工程文件
  • 四、HAL库实现
  • 01 安装 STM32CubeMX
  • 02 安装HAL库
  • 03 新建工程
  • 04 Keil仿真调试
  • 五、硬件连接
  • 六、逻辑仿真分析
  • 七、总结
  • 参考资料
  • 一、题目描述

    假设你手中已有 STM32最小系统核心板(STM32F103C8T6)+面板板+3只红绿蓝LED,并搭建了电路,分别GPIOA-5、GPIOB-9、GPIOC-14 这3个引脚上控制LED灯(最高时钟2Mhz),轮流闪烁,间隔时长1秒。

    1)写出程序设计思路,包括GPIOx端口的各寄存器地址和详细参数;

    2)用C语言 寄存器方式编程实现。

    3)安装 stm32CubeMX,用cubemx完成初始化过程,采用HAL库编程实现。

    4)在Keil下用软件仿真运行上面代码,并用虚拟逻辑分析仪观察 对应管脚上的输出波形(高低电平转换),看是否是1秒的周期。

    二、设计思路

    外设的功能都是完全不同的,但初始化都是大同小异的。
    点灯是所有学单片机的人都应该学会的第一项技能,这样子才算入门。

    51单片机的点灯是,通过控制寄存器将片外引脚(我们称之为IO口)拉低拉高,输出高低电平,以控制LED亮灭。
    其过程:单片机给指令->控制寄存器->给IO口电平->控制LED亮灭

    stm32的点灯则是,通过使能外设GPIO时钟,发出指令给外设GPIO,外设GPIO收到指令后,着手配置自己的寄存器,然后给IO口模式,让其实现各种功能。
    其过程:CPU给指令->GPIO收到指令->配置内部寄存器->配置IO口模式(注意是模式)->控制LED亮灭

    三、寄存器实现

    01 时钟配置

    使用PA6的端口,在面包板相应端口上接上LED灯

  • 首先要配置时钟使能。
  • 为什么配置时钟?为了省电,默认的时钟都是关闭的。配置STM32的任何资源前,都必须首先使能时钟。

  • 配置哪个时钟?
  • 时钟的信息在参考手册里边,参考手册十分巨大,不用通读,就像一个字典,需要什么查什么。

  • 参考手册,搜索"时钟",在表1里可以看到。
  • 时钟控制名字叫做RCC,属于AHB总线。GPIOA属于APB2。

    我们已经知道,GPIO端口A的地址从0x4001 0800开始。接下来只寻找时钟使能寄存器的地址:
      复位和时钟控制RCC的地址从0x4002 1000开始;
      可以在6.3.7小节找到APB2外设时钟使能寄存器(RCC_APB2ENR),偏移地址是0x18,所以APB2的地址就是0x4002 1018。
      看手册RCC_APB2ENR,位2是IOPAEN,名字是IO端口A时钟使能,就是我们想要的。

    把RCC_APB2ENR的位2赋值为1,就是开启GPIOA时钟。

    02 模式设置

  • 配置为通用输出
  • 既然叫做IO,那么肯定就是可以输入,可以输出,到底是输入还是输出呢?
      控制LED需要输出高电平或是低电平,所以需要配置为输出。
      由于STM32的每个IO都需要4个位来配置,所以一个32位的寄存器最大只能配置8个IO(32位的单片机的寄存器就是32位的)。STM32中,用端口配置低寄存器(GPIOx_CRL)来配置引脚Px0-Px7, 用端口配置高寄存器(GPIOx_CRH)来配置引脚Px8-Px15。
      配置引脚PA6,使用的寄存器是GPIOA_CRH。下面我们来寻找这个寄存器的地址。

  • 点亮LED需要输出高电平
  • 在单片机的编程中,要想做某件事,必须寻找相应的寄存器。在8.2.4小节,可以找到端口输出数据寄存器,就是我们需要的。我们需要输出1(主要看面包板上LED灯的正负极怎么接)其他两个寄存器的寻找方法与之类似。

    03 代码编写

    led.c

    #include "led.h"
    //初始化PA5 PB9 PC14为输出口.并使能这三个口的时钟 
    //LED IO 初始化
    void LED_Init(void)
    {
    	RCC->APB2ENR|=1<<2; //使能 IOPA 时钟 
    	RCC->APB2ENR|=1<<3; //使能 IOPB 时钟 
    	RCC->APB2ENR|=1<<4; //使能 IOPC 时钟
    //	RCC->APB2ENR|=1<<5; //使能 IOPD 时钟	
    
    	GPIOA->CRL&=0XFF0FFFFF; 
    	GPIOA->CRL|=0X00300000;//PA.5 推挽输出 
    	GPIOA->ODR|=1<<5; //PA.5 输出高
    	
    	GPIOB->CRH&=0XFFFFFF0F; 
    	GPIOB->CRH|=0X00000030;//PB.9 推挽输出 9属于端口配置高位寄存器
    	GPIOB->ODR|=1<<9; //PB.9 输出高 
    	
    	GPIOC->CRH&=0XF0FFFFFF; 
    	GPIOC->CRH|=0X03000000;//PC.14 推挽输出 
    	GPIOC->ODR|=1<<14; //PC.14 输出高
    }
    

    led.h

    #ifndef __LED_H
    #define __LED_H
    #include "sys.h"
    //LED 端口定义
    #define LED0 PAout(5) // DS0
    #define LED1 PBout(9) // DS1
    #define LED2 PCout(14) // DS2
    void LED_Init(void); //初始化 
    #endif
    

    test.c

    #include "sys.h"
    #include "delay.h"
    #include "led.h"
    int main(void)
    { 
    	Stm32_Clock_Init(9); //系统时钟设置
    	delay_init(72); //延时初始化
    	LED_Init(); //初始化与 LED 连接的硬件接口
    	while(1)
    	{
    		LED0=0;
    		LED1=1;
    		LED2=1;
    		delay_ms(1000);
    		LED0=1;
    		LED1=0;
    		LED2=1;
    		delay_ms(1000);
    		LED0=1;
    		LED1=1;
    		LED2=0;
    		delay_ms(1000);
    	} 
    }
    

    04 创建工程文件

    新建工程,选择F103C8

    基本配置

    加入启动配置文件

    新建以下文件并将启动文件加入目录,这时候我们发现这里报错,没有"sys.h"系统文件

    添加系统配置文件“Manage Project Items…”

    添加两个组:

    点击魔术棒,生成HEX文件

    加入sys、delay、usart的include路径:


    在文件夹中添加system_stm32f10x.c可以解决..\OBJ\test.axf: Error: L6218E: Undefined symbol SystemInit (referred from startup_stm32f10x_hd.o).的错误。所以说大家有问题可以多百度解决一哈。

    在创建工程这里需要耗费很多精力,所以还是建议大家可以找一个靠谱的模板文件,每次都复制模板文件夹,不用重复新建这些文件。

    四、HAL库实现

    01 安装 STM32CubeMX

    笔者在假期观看B站完成安装,有很多依附环境,一点点复杂。但祝愿大家都可以成功安装

    02 安装HAL库

    1. 打开安装好的STMCubeMX,点击HELP->Manage embedded software packages :
    2. 会跳出来一个选择型号界面 勾选上你要安装的HAL库, 点击“Install Now” 直到安装成功。 如下图(笔者已经安装过一种,图片仅做演示)

    03 新建工程

    1. 回到STMCubeMX的主界面,创建新项目:
    2. 在part name里选择自己的芯片,点击信息栏中的具体芯片信息选中,点击start project。(包装方式TR:带卷;无特性:盘装)
    3. 点击system core,进入SYS,在debug下选择serial wire:
    4. 配置时钟,进入上面的rcc,有两个时钟,一个是hse和lse,我们要用是GPIO接口,而这些接口都在APB2里:

      接下来观察时钟架构,APB2总线的时钟由hse控制,同时在这个界面得把PLLCLK右边选上:
    5. 将hse那里设为Crystal/Ceramic Resonator:
    6. 接下来就是点击相应的引脚设置输出寄存器了,就是output那一项,一共选了三个,是PA5,PB9,PC14:
    7. 点击project manager,配置好自己的路径和项目名,然后IDE那项改为MDK-ARM:
    8. 进入 code generate界面,选择生成初始化.c/.h文件,后面点击generate code,选择open project,然后就到KEIL5了

    04 Keil仿真调试

    打开Keil文件,在main函数中找到while循环:

    在循环中写入以下代码:

      while (1)
      {
        /* USER CODE END WHILE */
    
        /* USER CODE BEGIN 3 */ //用户代码开始部分
    
    	
    		HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_RESET);//PA5亮灯
    		HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_SET);//PB9熄灯
    		HAL_GPIO_WritePin(GPIOC,GPIO_PIN_14,GPIO_PIN_SET);//PC14熄灯
    		HAL_Delay(1000);//延时1s
    		HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET);//PA5熄灯
    		HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_RESET);//PB9亮灯
    		HAL_GPIO_WritePin(GPIOC,GPIO_PIN_14,GPIO_PIN_SET);//PC14熄灯
    		HAL_Delay(1000);//延时1s		
    		HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET);//PA5熄灯
    		HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_SET);//PB9熄灯
    		HAL_GPIO_WritePin(GPIOC,GPIO_PIN_14,GPIO_PIN_RESET);//PC14亮灯
    		HAL_Delay(1000);//延时1s
    
      }
      /* USER CODE END 3 *///用户代码结束部分
    

    五、硬件连接

    wait

    六、逻辑仿真分析

    1. Target界面中,选择跟正确的晶振大小,我使用的是8MHz的外部晶振。这个选项在软件仿真中起到很重要的作用,如果选择错误,那么波形一定是错误的,因为时间不准确。
    2. Debug页的设置:
    3. 点击Debug,进入调试界面, 选择逻辑分析仪
    4. 选择要观察的引脚:点击Setup Logic Analyzer
    5. 增加要观察的引脚

    1. 相关设置

    2. 运行程序

    3. 观察波形

      可以看到三个引脚交替101、011、110

    七、总结

    寄存器和HAL库相比之下,还是HAL库更加方便。寄存器查找位置,翻阅文件十分复杂。通过这次学习能够更深刻学到STM32编程的意义。也希望早日上实物操作,锻炼动手能力。

    参考资料

    1、STM32F103C8T6寄存器方式借助面包板点亮LED流水灯详解
    2、stm32cubeMX使用HAL库点亮LED流水灯

    物联沃分享整理
    物联沃-IOTWORD物联网 » 使用STM32点亮LED

    发表评论