STM32H750VBT6工程模板搭建说明
一、模版功能说明
该模板的目的是在STM32H750VBT6核心板上搭建起基本的单片机环境,包括时钟配置、串口配置、时钟输出以及LED亮灭等功能,单片机有了基本的工作和开发条件则便于后续相关工程的编写。
该工程使用LL库进行编程,为什么使用LL库呢?首先ST官方已经停止维护标准库,之前我在使用STM32F103时是使用的标准库来开发,但是STM32H750并没有官方的标准库进行使用,只有HAL库和LL库。但是HAL库过于抽象,效率较低,而LL库较为接近底层,和标准库相近,因此选用LL库进行开发。
二、模板编程过程
1,最初:
(1) ST官网下载了LL库进行开发。
(2) STM32H7B3xQ HAL User Manual上查看LL库相关的SDK手册,便于了解LL库所用的外设,结构体,函数等功能。虽然名字和STM32H750不符合,但是STM32H7B3xQ HAL User Manual中的LL库相关的介绍是与STM32H750兼容的。
(3) STM32H750开发手册上查看寄存器定义和功能,以及外设介绍等相关内容。
(4) 正点原子STM32H750的资料中查找相关例程作为参考。
三、工程KEIL配置
图3-1 KEIL配置Target
IROM的地址和大小要与STM32H750相匹配,这个地址就是单片机程序的起始地址。因为我在编译正点原子例程时使用ARMv6编译器有报错的情况,所以我在这里使用ARMv5编译器。但是要注意最新版本keil没有ARMv5编译器,需要手动下载安装。
图3-2 KEIL配置Output
选中了Browse Information,选中这个方便查看函数定义。
图3-3 KEIL配置C/C++
最重要的是Define部分,宏定义了STM32H750xx,指定包含头文件stm32h750xx.h。同样宏定义了USE_FULL_LL_DRIVER,才能完整的使用LL库。
图3-4 KEIL配置Debug->右侧Settings->Flash Download
勾选了Reset and Run,才能在烧录完成后自动运行该程序。
四、STM32工程启动流程
单片机上电后自动运行startup_stm32h750xx.s中的汇编代码,从第1行到第230行,都是定义操作,比如定义了栈,堆,中断向量。
然后开始运行SystemInit函数,SystemInit函数在system_stm32h7xx.c中定义,是LL库本身就提供的,不需要修改,主要是定义了FLASH,启动了内部时钟等相关操作,让单片机有了运行程序的最基本的条件。
运行了SystemInit之后,然后进入main函数,也就是我们所编写的代码。
五、工程代码讲解
1,时钟配置,system_init函数
系统初始化函数,用于配置系统的状态。主要是开启了I-Cache,D-Cache,然后配置单片机供电,配置时钟选择HSE,也就是外部高速晶振,然后HSE进入PLL1,PLL1对输入时钟进行5分频,160倍频,然后P路2分频。P路输出的时钟就作为主频,也就是说25MHz外部晶振经过PLL1变成了400MHz。400MHz就是主频。
因为外设都是挂在AHB,APB上的,所有的AHB时钟频率都一样,APB时钟频率可以不一样,具体要看分频系数,在本工程中配置AHB均为主频的2分频也就是200MHz,配置所有的APB时钟为AHB的2分频也就是100MHz。配置完成后需要声明一下主频为400MHz,并且开启sysclk时钟,用于延时。
Sysclk也是一个外设,也是挂在时钟总线上的,如何找到外设所在时钟总线呢?可以在STM32H7B3xQ HAL User Manual的目录中点击Modules->STM32H7xx_LL_Driver->BUS->
Bus Exported Constans中找到。
至此system_init函数的功能完成,主要就是配置时钟树,在STM32CubeMX中进行GUI配置更为方便直观。
2,串口配置
串口选择串口1,流程就是开启串口时钟以及串口所在GPIO口的时钟,配置串口时钟源,配置GPIO的复用功能,使得GPIO映射到串口引脚,使能串口中断,配置串口参数,最后进行使能即可。
3,其它外设如GPIO,MCO等
GPIO配置主要是配置LED,观察LED的亮灭从而验证单片机状态。
MCO的匹配主要是输出HSE时钟,如果示波器看出有时钟输出并且频率正确,那么单片机也是正常工作的并且HSE工作正常。MCO输出频率定义为HSE的十分频,也就是25Mhz/10。如果仅仅是用于观察时钟状态,那么分频数越高越好。分频数越高,MCO输出时钟的频率越低,示波器观察越清楚。不过输出的信号是方波,毕竟经过了内部电路进行调整,但是HSE输入的时钟肯定是正弦。
其它外设的配置流程大体一致,基本上都是定义结构体,使能时钟,初始化结构体后对外设进行配置,如果有中断就配置中断优先级,编写中断函数,然后进行使能并且等待配置完成即可。
六、要点
1,时钟配置是参照stm32h750开发手册的rcc模块进行编写的。GPIO口复用功能映射表在stm32h750vb 中可以找到。
2,关于中断函数
在串口配置中我使能了串口接收中断,并且中断优先级最低。串口1的中断函数名称一定是USART1_IRQHandler,因为在startup_stm32h750xx.s中定义的串口1中断函数就是USART1_IRQHandler。
我定义了一个串口缓冲区,因为在main函数的while(1)循环中,每次执行的代码都是一样的,如果串口发送的数据是有规律的,那么每次循环中串口接收的数据所占缓冲区的位置是一样的,那么就可以统一进行读取与处理,读取后立刻清除缓冲区即可,这样可以极大的提高效率。如果发送的数据是没有规律的,那么就用USART_Read_Newest_Byte函数读取串口最新发送的数据即可。
3,关于串口发送浮点数等多字节数据
串口大多设置成8位1停止,这样最高发送的数据也就是255,那么如果发送的数据为10000000,或者是1.234567浮点数该怎么办呢?一种办法是用sprintf转成字符串发送,发送后再转换为数据。还有一种方法就是发多个字节,比如我定义double a = 1.23456,double 占据8个字节,假设a的地址为0x1000,八个字节就是0x1000~0x1007,假设里面的内容是0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88。利用uint8_t指针b=a的地址,那么b=0x11,(b+1)=0x22,…………*(b+7)=0x88,然后连续发送8个字节,在接收端同样定义一个double 数据,利用uint8指针指向double数据的地址,分别接收8个字节依次对double数据的地址赋值,这样即完成了浮点数据的传输。这种传输方式同样可以完成2字节(short int),4字节(int,float)等数据的传输,原理是一样的,具体函数在usart.c有展示。
为什么要定义uint8_t指针呢,因为uint8_t数据类型仅占据一个字节,这样定义的地址b=0x1000,b+1=0x1001。如果定义成double指针b,那么该指针所指数据则占据八个字节,那么b=0x1000,b+1就等于0x1008了。不过我建议如果不是大批量的数据,还是利用字符串传递较为方便。
4,关于串口发送字符串
正点原子是直接重映射printf函数,我则是自己定义了字符串发送函数,因为字符串默认最后一位停止位为’\0‘,所以检测到’\0’进行发送。
5 关于system_init.h中的宏定义
为了保证程序的通用性,我将所用到的外设和引脚都在其中利用宏定义进行声明,如果需要改变引脚,仅需要再宏定义中进行修改即可,不需要动程序,这样的移植性比较强。
七、工程下载
链接:https://pan.baidu.com/s/1XNJA1oIAOu2lXOKjdd9Fkg?pwd=1234
提取码:1234