因本人在上次实验中已经采用了寄存器方式(汇编、c语言)成功完成了LED流水灯实验,可参考我的另外一篇博客Keil下STM32的C与汇编语言混合编程,这里就不再介绍了。
(1)安装jdk
jdk下载链接:https://www.oracle.com/java/technologies/javase-downloads.html
jdk为stm32CubeMx的实现环境。
(2)安装STM32CubeMX
下载官网:
https://www.st.com/en/development-tools/stm32cubemx.html
需要邮箱登录,进行直接下载。
①打开并运行安装STM32CubeMX-4.27.0.exe ,点击next如图1所示。
图 1 STM32CebeMx安装开始界面
②点击"I accept the terms of this license agreement",接着选择Next。如图2所示。
图2 同意安装
③省略中间next步骤,最后一步安装完成后出现界面,点击done,完成安装,如图3所示 。
图3 安装完成
(1)安装固件库
①、运行CubeMx,选择Help再点击Magne安装固件库,如图4所示。
图4 安装固件库
②选择STM32F1安装1.8.3版本,安装完成,如图5所示。
①点击File,再点击New Project。
如图6所示
图6 新建工程
②选择相应芯片,我选的STM32F103C8。
如图7所示。
图7 选择芯片
③配置时钟晶振,点击RCC。
如图8、图9所示
图8 选择晶振
修改频率为72MHZ
图9 修改频率
④修改PA1、PA3、PA5引脚状态output
如图10所示
图10 修改管脚状态
⑤修改项目路径,为自己熟悉的路径
如图11、12所示。
图11 修改路径
图12 生成代码
⑥工程创建完成打开keil,如图13所示
图 13 打开工程
在while循环中添加代码:
while (1)
{
/* USER CODE END WHILE */
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_1,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_3,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET);
HAL_Delay(1000);
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_1,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_3,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET);
HAL_Delay(1000);
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_1,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_3,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_RESET);
HAL_Delay(1000);
/* USER CODE BEGIN 3 */
}
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_1,GPIO_PIN_RESET)
;为写管脚函数。
使用方法:函数原型:void HAL_GPIO_WritePin (GPIO_TypeDef * GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState)
. 为(管脚组号,管脚编号,管脚状态)。
GPIO_BIT_RESET表示0(低电平) GPIO_BIT_SET表示1(高电平)
LED流水灯为低电平亮,高电平熄灭。
HAL_Delay()为延迟函数,单位是ms。
①仿真参数设置
点击target修改频率为8.0MHz,再点击Debug修改仿真参数Dialog DLL和Paramter在点击如图14所示。
图14 参数设置
②设置仿真示波器参数
如图15所示。
图15 示波器参数
③仿真截图,如图16所示。
图16 仿真结果
通过仿真波形可得,其仿真结果的时序状态所反应的LED流水灯闪烁状态正确,低电平LED灯亮,所以是PA1、PA3、PA5三个管脚交替闪烁。此LED灯闪烁周期为3.048s。
①接线烧录
此过程参考我上一篇文章STM32串口下载
②实验结果
①代码编写
;RCC寄存器地址映像
RCC_BASE EQU 0x40021000
RCC_CR EQU (RCC_BASE + 0x00)
RCC_CFGR EQU (RCC_BASE + 0x04)
RCC_CIR EQU (RCC_BASE + 0x08)
RCC_APB2RSTR EQU (RCC_BASE + 0x0C)
RCC_APB1RSTR EQU (RCC_BASE + 0x10)
RCC_AHBENR EQU (RCC_BASE + 0x14)
RCC_APB2ENR EQU (RCC_BASE + 0x18)
RCC_APB1ENR EQU (RCC_BASE + 0x1C)
RCC_BDCR EQU (RCC_BASE + 0x20)
RCC_CSR EQU (RCC_BASE + 0x24)
;AFIO寄存器地址映像
AFIO_BASE EQU 0x40010000
AFIO_EVCR EQU (AFIO_BASE + 0x00)
AFIO_MAPR EQU (AFIO_BASE + 0x04)
AFIO_EXTICR1 EQU (AFIO_BASE + 0x08)
AFIO_EXTICR2 EQU (AFIO_BASE + 0x0C)
AFIO_EXTICR3 EQU (AFIO_BASE + 0x10)
AFIO_EXTICR4 EQU (AFIO_BASE + 0x14)
;GPIOA寄存器地址映像
GPIOA_BASE EQU 0x40010800
GPIOA_CRL EQU (GPIOA_BASE + 0x00)
GPIOA_CRH EQU (GPIOA_BASE + 0x04)
GPIOA_IDR EQU (GPIOA_BASE + 0x08)
GPIOA_ODR EQU (GPIOA_BASE + 0x0C)
GPIOA_BSRR EQU (GPIOA_BASE + 0x10)
GPIOA_BRR EQU (GPIOA_BASE + 0x14)
GPIOA_LCKR EQU (GPIOA_BASE + 0x18)
;GPIO C口控制
GPIOC_BASE EQU 0x40011000
GPIOC_CRL EQU (GPIOC_BASE + 0x00)
GPIOC_CRH EQU (GPIOC_BASE + 0x04)
GPIOC_IDR EQU (GPIOC_BASE + 0x08)
GPIOC_ODR EQU (GPIOC_BASE + 0x0C)
GPIOC_BSRR EQU (GPIOC_BASE + 0x10)
GPIOC_BRR EQU (GPIOC_BASE + 0x14)
GPIOC_LCKR EQU (GPIOC_BASE + 0x18)
;串口1控制
USART1_BASE EQU 0x40013800
USART1_SR EQU (USART1_BASE + 0x00)
USART1_DR EQU (USART1_BASE + 0x04)
USART1_BRR EQU (USART1_BASE + 0x08)
USART1_CR1 EQU (USART1_BASE + 0x0c)
USART1_CR2 EQU (USART1_BASE + 0x10)
USART1_CR3 EQU (USART1_BASE + 0x14)
USART1_GTPR EQU (USART1_BASE + 0x18)
;NVIC寄存器地址
NVIC_BASE EQU 0xE000E000
NVIC_SETEN EQU (NVIC_BASE + 0x0010)
;SETENA寄存器阵列的起始地址
NVIC_IRQPRI EQU (NVIC_BASE + 0x0400)
;中断优先级寄存器阵列的起始地址
NVIC_VECTTBL EQU (NVIC_BASE + 0x0D08)
;向量表偏移寄存器的地址
NVIC_AIRCR EQU (NVIC_BASE + 0x0D0C)
;应用程序中断及复位控制寄存器的地址
SETENA0 EQU 0xE000E100
SETENA1 EQU 0xE000E104
;SysTick寄存器地址
SysTick_BASE EQU 0xE000E010
SYSTICKCSR EQU (SysTick_BASE + 0x00)
SYSTICKRVR EQU (SysTick_BASE + 0x04)
;FLASH缓冲寄存器地址映像
FLASH_ACR EQU 0x40022000
;SCB_BASE EQU (SCS_BASE + 0x0D00)
MSP_TOP EQU 0x20005000
;主堆栈起始值
PSP_TOP EQU 0x20004E00
;进程堆栈起始值
BitAlias_BASE EQU 0x22000000
;位带别名区起始地址
Flag1 EQU 0x20000200
b_flas EQU (BitAlias_BASE + (0x200*32) + (0*4))
;位地址
b_05s EQU (BitAlias_BASE + (0x200*32) + (1*4))
;位地址
DlyI EQU 0x20000204
DlyJ EQU 0x20000208
DlyK EQU 0x2000020C
SysTim EQU 0x20000210
;常数定义
Bit0 EQU 0x00000001
Bit1 EQU 0x00000002
Bit2 EQU 0x00000004
Bit3 EQU 0x00000008
Bit4 EQU 0x00000010
Bit5 EQU 0x00000020
Bit6 EQU 0x00000040
Bit7 EQU 0x00000080
Bit8 EQU 0x00000100
Bit9 EQU 0x00000200
Bit10 EQU 0x00000400
Bit11 EQU 0x00000800
Bit12 EQU 0x00001000
Bit13 EQU 0x00002000
Bit14 EQU 0x00004000
Bit15 EQU 0x00008000
Bit16 EQU 0x00010000
Bit17 EQU 0x00020000
Bit18 EQU 0x00040000
Bit19 EQU 0x00080000
Bit20 EQU 0x00100000
Bit21 EQU 0x00200000
Bit22 EQU 0x00400000
Bit23 EQU 0x00800000
Bit24 EQU 0x01000000
Bit25 EQU 0x02000000
Bit26 EQU 0x04000000
Bit27 EQU 0x08000000
Bit28 EQU 0x10000000
Bit29 EQU 0x20000000
Bit30 EQU 0x40000000
Bit31 EQU 0x80000000
;向量表
AREA RESET, DATA, READONLY
DCD MSP_TOP ;初始化主堆栈
DCD Start ;复位向量
DCD NMI_Handler ;NMI Handler
DCD HardFault_Handler ;Hard Fault Handler
DCD 0
DCD 0
DCD 0
DCD 0
DCD 0
DCD 0
DCD 0
DCD 0
DCD 0
DCD 0
DCD 0
DCD SysTick_Handler ;SysTick Handler
SPACE 20 ;预留空间20字节
;代码段
AREA |.text|, CODE, READONLY
;主程序开始
ENTRY
;指示程序从这里开始执行
Start
;时钟系统设置
ldr r0, =RCC_CR
ldr r1, [r0]
orr r1, #Bit16
str r1, [r0]
;开启外部晶振使能
;启动外部8M晶振
ClkOk
ldr r1, [r0]
ands r1, #Bit17
beq ClkOk
;等待外部晶振就绪
ldr r1,[r0]
orr r1,#Bit17
str r1,[r0]
;FLASH缓冲器
ldr r0, =FLASH_ACR
mov r1, #0x00000032
str r1, [r0]
;设置PLL锁相环倍率为7,HSE输入不分频
ldr r0, =RCC_CFGR
ldr r1, [r0]
orr r1, #(Bit18 :OR: Bit19 :OR: Bit20 :OR: Bit16 :OR: Bit14)
orr r1, #Bit10
str r1, [r0]
;启动PLL锁相环
ldr r0, =RCC_CR
ldr r1, [r0]
orr r1, #Bit24
str r1, [r0]
PllOk
ldr r1, [r0]
ands r1, #Bit25
beq PllOk
;选择PLL时钟作为系统时钟
ldr r0, =RCC_CFGR
ldr r1, [r0]
orr r1, #(Bit18 :OR: Bit19 :OR: Bit20 :OR: Bit16 :OR: Bit14)
orr r1, #Bit10
orr r1, #Bit1
str r1, [r0]
;其它RCC相关设置
ldr r0, =RCC_APB2ENR
mov r1, #(Bit14 :OR: Bit4 :OR: Bit2)
str r1, [r0]
;IO端口设置
ldr r0, =GPIOC_CRL
ldr r1, [r0]
orr r1, #(Bit28 :OR: Bit29)
;PC.7输出模式,最大速度50MHz
and r1, #(~Bit30 & ~Bit31)
;PC.7通用推挽输出模式
str r1, [r0]
;PA9串口0发射脚
ldr r0, =GPIOA_CRH
ldr r1, [r0]
orr r1, #(Bit4 :OR: Bit5)
;PA.9输出模式,最大速度50MHz
orr r1, #Bit7
and r1, #~Bit6
;10:复用功能推挽输出模式
str r1, [r0]
ldr r0, =USART1_BRR
mov r1, #0x271
str r1, [r0]
;配置波特率-> 115200
ldr r0, =USART1_CR1
mov r1, #0x200c
str r1, [r0]
;USART模块总使能 发送与接收使能
;71 02 00 00 2c 20 00 00
;AFIO 参数设置
;Systick 参数设置
ldr r0, =SYSTICKRVR
;Systick装初值
mov r1, #9000
str r1, [r0]
ldr r0, =SYSTICKCSR
;设定,启动Systick
mov r1, #0x03
str r1, [r0]
;NVIC
;ldr r0, =SETENA0
;mov r1, 0x00800000
;str r1, [r0]
;ldr r0, =SETENA1
;mov r1, #0x00000100
;str r1, [r0]
;切换成用户级线程序模式
ldr r0, =PSP_TOP
;初始化线程堆栈
msr psp, r0
mov r0, #3
msr control, r0
;初始化SRAM寄存器
mov r1, #0
ldr r0, =Flag1
str r1, [r0]
ldr r0, =DlyI
str r1, [r0]
ldr r0, =DlyJ
str r1, [r0]
ldr r0, =DlyK
str r1, [r0]
ldr r0, =SysTim
str r1, [r0]
;主循环
main
ldr r0, =Flag1
ldr r1, [r0]
tst r1, #Bit1
;SysTick产生0.5s,置位bit 1
beq main ;0.5s标志还没有置位
;0.5s标志已经置位
ldr r0, =b_05s
;位带操作清零0.5s标志
mov r1, #0
str r1, [r0]
bl LedFlas
mov r0, #'H'
bl send_a_char
mov r0, #'e'
bl send_a_char
mov r0, #'l'
bl send_a_char
mov r0, #'l'
bl send_a_char
mov r0, #'o'
bl send_a_char
mov r0, #' '
bl send_a_char
mov r0, #'w'
bl send_a_char
mov r0, #'i'
bl send_a_char
mov r0, #'n'
bl send_a_char
mov r0, #'d'
bl send_a_char
mov r0, #'o'
bl send_a_char
mov r0, #'w'
bl send_a_char
mov r0, #'s'
bl send_a_char
mov r0, #'!'
bl send_a_char
mov r0, #'\n'
bl send_a_char
b main
;子程序 串口1发送一个字符
send_a_char
push {r0 - r3}
ldr r2, =USART1_DR
str r0, [r2]
b1
ldr r2, =USART1_SR
ldr r2, [r2]
tst r2, #0x40
beq b1
;发送完成(Transmission complete)等待
pop {r0 - r3}
bx lr
;子程序 led闪烁
LedFlas
push {r0 - r3}
ldr r0, =Flag1
ldr r1, [r0]
tst r1, #Bit0
;bit0 闪烁标志位
beq ONLED ;为0 打开led灯
;为1 关闭led灯
ldr r0, =b_flas
mov r1, #0
str r1, [r0]
;闪烁标志位置为0,下一状态为打开灯
;PC.7输出0
ldr r0, =GPIOC_BRR
ldr r1, [r0]
orr r1, #Bit7
str r1, [r0]
b LedEx
ONLED
;为0 打开led灯
ldr r0, =b_flas
mov r1, #1
str r1, [r0]
;闪烁标志位置为1,下一状态为关闭灯
;PC.7输出1
ldr r0, =GPIOC_BSRR
ldr r1, [r0]
orr r1, #Bit7
str r1, [r0]
LedEx
pop {r0 - r3}
bx lr
;异常程序
NMI_Handler
bx lr
HardFault_Handler
bx lr
SysTick_Handler
ldr r0, =SysTim
ldr r1, [r0]
add r1, #1
str r1, [r0]
cmp r1, #500
bcc TickExit
mov r1, #0
str r1, [r0]
ldr r0, =b_05s
;大于等于500次 清零时钟滴答计数器 设置0.5s标志位
;位带操作置1
mov r1, #1
str r1, [r0]
TickExit
bx lr
ALIGN
;通过用零或空指令NOP填充,来使当前位置与一个指定的边界对齐
END
①仿真参数设置与流水灯一致,如图14所示。
②设置仿真示波器参数
③仿真结果,如图17所示。
图17 仿真结果
①创建工程
在CubeMx中创建一个新的工程,选择相应的芯片,工程生成过程与流水灯的生成过程一致,只是参数不同,此工程不需要设置GPIOx管脚状态。直接生成初始工程。
②添加hello windows代码
在main函数中的while循环中添加代码:
char data[]="hello windows!\n";
HAL_UART_Transmit(&huart1, (uint8_t *)data, 15, 0xffff);
HAL_Delay(1000);
HAL_UART_Transmit();
串口发送数据,使用超时管理机制 。如果超时没发送完成,则不再发送,返回超时标志。
函数原型:HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)
huart1为默认uart串口别名,(uint8_t *)data,x
为串口发送15个字节数据,就是data数组中的hello windows!最大传输时间为0xffff。
①仿真参数设置与流水灯一致,如图14所示。
②设置仿真示波器参数,如图18所示。
图18 参数设置
③仿真结果,如图19所示。
图19 仿真结果
周期约等于1s。
通用同步异步收发器(USART)提供了一种灵活的方法与使用工业标准NRZ异步串行数据格式的外部设备之间进行全双工数据交换。USART利用分数波特率发生器提供宽范围的波特率选择。
它支持同步单向通信和半双工单线通信,也支持LIN(局部互连网),智能卡协议和IrDA(红外数据 组织)SIRENDEC规范,以及调制解调器(CTS/RTS)操作。串口通信一般是以帧格式传输数据,即一帧一帧传输,每帧包含有起始信号、数据信息、停止信息,可能还有校验信息。
串行通信数据按位顺序传输,占用引脚资源少,速度相对较慢。
接口通过三个引脚与其他设备连接在一起。任何USART双向通信至少需要两个脚:接收数据输入(RX)和发送数据输出(TX)。
RX:接收数据串行输。通过过采样技术来区别数据和噪音,从而恢复数据。
TX:发送数据输出。当发送器被禁止时,输出引脚恢复到它的I/O端口配置。当发送器被激活,并且不发送数据时,TX引脚处于高电平。在单线和智能卡模式里,此I/O口被同时用于数据的发送和接收。
经过电平转换后,芯片串口和rs232的电平标准是不一样的:
单片机的电平标准(TTL电平):+5V表示1,0V表示0;
Rs232的电平标准:+15/+13 V表示0,-15/-13表示1。
2、完成一个STM32的USART串口通讯程序(查询方式即可,暂不要求采用中断方式),要求:
1)设置波特率为115200,1位停止位,无校验位;
2)STM32系统给上位机(win10)连续发送“hello windows!”。win10采用“串口助手”工具接收。
(1)下载串口调试助手
各种版本下载地址(复制到浏览器打开直接下载):
下载地址1:https://sourceforge.net/projects/firetools (境外,sourceforge,包含Windows版本、Ubuntu版本)
下载地址2:https://pan.baidu.com/s/14zEjYNlU-2CjgoR1sI5dSg 提取码:rau0 (百度云下载,包含Windows版本、Ubuntu版本)
下载地址3:https://cloud.embedfire.com/software/FireTools/fireTools-win64-v1.0.1.5.zip (阿里云下载,只含Windows版本)
下载地址4:https://cloud.embedfire.com/software/FireTools/fireTools.deb (阿里云下载,只含Ubuntu版本)
(2)接线、烧录
①接线,如图21所示。
图21 串口接线
GND——GND、3V3——3V3、RXD——PA9、TXD——PA10
②烧录
此过程可参考流水灯操作,有详细的步骤介绍。
(3)串口调试查看结果
如图22所示。
图22串口输出
本实验主要完成对串口的了解、运用及安装CebeMx使用HAL库函数完成代码编写,简化了我们的操作过程,对于代码的编写也简单了很多,HAL库是ST公司针对STM32单片机推出的全新开发库,旨在取代原来用于开发STM32的标准库。相比于原来的标准库,具有一定的优点,比如:HAL库开发提供了图形化配置界面,使得外设初始化变得更加简单明了且不容易出错;HAL库提供了更高抽象层次的API。相对于上一个对于寄存器编写代码的实验简单了很多。对于串口,我也是本次实验才真正的进行了了解,串口的功能特性、要求还有很多在本实验中虽然没有用到,但也学习了很多,为以后学习增添了知识基础。本次实验较为简单,流水灯实验也在上次已经完成过了一次,所以整个操作过程还算简单,如有错误,请指正。
【1】STM32中文参考手册
【2】【STM32】串口通信基本原理(超基础、详细版)
【3】搭建STM32开发环境——STM32CubeMX,Keil5
【4】HAL库 STM32CubeMx系列学习教程