您的位置:首页 > 编程语言 > Java开发

关于STM32的一些开发技巧

2017-03-10 00:00 1016 查看

流行IDE

Keil

老牌编译器,结合SourceInsight用应该是大众所常用的开发方式吧!

IAR

老牌编译器,这个还是以前在学校用MSP430时接触的。一样功能比较强大,特别一点,编译出来的hex比其它编译器要小。

sw4stm32

基于Eclipse开发的一个STM32专用IDE,似乎是官网推荐。好处是免费,结合STM32Cube的插件使用,开发STM32程序即为方便。

缺点是资料较少,使用的人群没有Keil、IAR多。

Atollic TrueSTUDIO(仅仅测过一下)

仅了解一下,这也是基于Eclipse开发的嵌入式IDE,支持很多MCU,不止STM32一种。分为免费版本和Pro版。有兴趣的童鞋可以详细了解一下。

STM32开发方式

官网提供了两套开发STM32的代码:

其一为stdperiph_lib,即我们所说的标准库;

其二为STM32CubeMx,这是一个基于HAL库的工具,如下图所示;



这种方式极为简化了STM32的开发,可以通过一些简单的配置,快速的生成代码。而且HAL库兼容了STM32各个系列,使得硬件改版后,软件代码的可移植性大大提高。

当然HAL也有不足之处,那便是过于复杂,看过其代码就知道其复杂性远非其它库所比。

它的复杂性带来的便是系统级的兼容。如你在用到嵌入式系统时,并不需要额外的参数及代码来保证各线程的冲突。HAL内部自带互斥、硬件读写锁。

比较建议的开发组合为:HAL+自己参考标准库写的一些硬件操作函数。下面简略介绍一下HAL库的常用开发方式。

基于HAL库开发

使用STM32CubeMx(或Eclipse的插件)生成工程后,其包含了所有的初始化代码及时钟配置代码。你只需要在工程中添加自己的逻辑代码即可。

如果包含系统(STM32Cube默认使用FreeRTOS),则可以删除src中的freertos.c文件,然后新建一个源码目录users,将freertos中的初始化函数“void MX_FREERTOS_Init()”,在自己的c文件中,重新定义一个即可。

这样做的好处是:以后再调整STM32Cube工程后,只需要删除freertos.c,不用更改一处代码即可正常编译执行。

下面说一说“HAL库的正确使用方式”(这部分基于FreeRTOS,无系统的代码大同小异),这主要包含两部分:

外设初始化

生成的初始化代码有三个函数:
void MX_I2C1_Init(void);
void HAL_I2C_MspInit(I2C_HandleTypeDef* i2cHandle);
void HAL_I2C_MspDeInit(I2C_HandleTypeDef* i2cHandle);
通过这三个函数调用,可以初始化外设以及功耗控制。

读写操作

HAL库提供三种读写方式:一是超时读写;二是中断读写;三是DMA读写。详见“stm32fxxx_hal_i2c.h”。

超时读写

HAL_StatusTypeDef HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_I2C_Master_Receive(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_I2C_Slave_Transmit(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_I2C_Slave_Receive(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_I2C_Mem_Write(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_I2C_Mem_Read(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size, uint32_t Timeout);
HAL_StatusTypeDef HAL_I2C_IsDeviceReady(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint32_t Trials, uint32_t Timeout);


中断读写

HAL_StatusTypeDef HAL_I2C_Master_Transmit_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_I2C_Master_Receive_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_I2C_Slave_Transmit_IT(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_I2C_Slave_Receive_IT(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_I2C_Mem_Write_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_I2C_Mem_Read_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_I2C_Master_Sequential_Transmit_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t XferOptions);
HAL_StatusTypeDef HAL_I2C_Master_Sequential_Receive_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t XferOptions);
HAL_StatusTypeDef HAL_I2C_Slave_Sequential_Transmit_IT(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size, uint32_t XferOptions);
HAL_StatusTypeDef HAL_I2C_Slave_Sequential_Receive_IT(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size, uint32_t XferOptions);
HAL_StatusTypeDef HAL_I2C_Master_Abort_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress);
HAL_StatusTypeDef HAL_I2C_EnableListen_IT(I2C_HandleTypeDef *hi2c);
HAL_StatusTypeDef HAL_I2C_DisableListen_IT(I2C_HandleTypeDef *hi2c);


DMA读写

HAL_StatusTypeDef HAL_I2C_Master_Transmit_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_I2C_Master_Receive_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_I2C_Slave_Transmit_DMA(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_I2C_Slave_Receive_DMA(I2C_HandleTypeDef *hi2c, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_I2C_Mem_Write_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size);
HAL_StatusTypeDef HAL_I2C_Mem_Read_DMA(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize, uint8_t *pData, uint16_t Size);


如何得到返回的读写数据长度呢?这个可以根据I2C_HandleTypeDef结构中的RxXferCount/RxXferSize、TxXferCount/TxXferSize做差得到。每发送或者接收一个数据,Count值会减1,而Size则是你传入的一个长度,Size减去Count即可得到返回的读写数据长度。

中断回调

HAL库不止提供了读写操作函数,还提供了一系列的中断回调。比如发送、接收、错误中断。

void HAL_I2C_EV_IRQHandler(I2C_HandleTypeDef *hi2c);
void HAL_I2C_ER_IRQHandler(I2C_HandleTypeDef *hi2c);
void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef *hi2c);
void HAL_I2C_MasterRxCpltCallback(I2C_HandleTypeDef *hi2c);
void HAL_I2C_SlaveTxCpltCallback(I2C_HandleTypeDef *hi2c);
void HAL_I2C_SlaveRxCpltCallback(I2C_HandleTypeDef *hi2c);
void HAL_I2C_AddrCallback(I2C_HandleTypeDef *hi2c, uint8_t TransferDirection, uint16_t AddrMatchCode);
void HAL_I2C_ListenCpltCallback(I2C_HandleTypeDef *hi2c);
void HAL_I2C_MemTxCpltCallback(I2C_HandleTypeDef *hi2c);
void HAL_I2C_MemRxCpltCallback(I2C_HandleTypeDef *hi2c);
void HAL_I2C_ErrorCallback(I2C_HandleTypeDef *hi2c);
void HAL_I2C_AbortCpltCallback(I2C_HandleTypeDef *hi2c);

注意:这些函数均在stm32fxxx_hal_i2c.c中有实现。如果需要某个中断回调,则需要查看这个文件中的函数是否有__weak修饰。有__weak修饰的函数表示这是一个虚拟函数,你可以在外部重新定义其实现。如果没有__weak修饰,如HAL_I2C_EV_IRQHandler,则表示这个函数被HAL库实现。

总结

总得来说,STM32开发建议使用如下方式:sw4stm32IDE+STM32Cube的Eclipse插件进行开发。如果不能满足需求,则读写、中断可以从标准库中拷贝过来,自己实现。

简单说就是:

使用STM32Cube的函数进行时钟和外设的初始化及其使能控制。

使用从标准库移植的代码实现外设的读写、中断操作。

由于HAL库和标准库有部分冲突,所以两个库并不能直接在一个工程中使用。除非修改库的代码。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  STM32 STM32Cube Eclipse