CoIDE版本:CoIDE-V2Beta
编译器版本:gcc-arm-none-eabi-5_2-2015q4
目标板:STM32F030C8T6
之前一直使用MDK开发STM32应用程序,近日想尝试下gcc编译STM32,享受下开源的果实,于是乎在网上了解到了coocox,它有一个CoIDE用来编辑代码,是简版的eclipse,目前最新版为V2Beta,之前用eclipse生成注释很方便,所以就想试试CoIDE是否也可以,但尝试了半天也没搞定,始终无法自动生成注释。。。
coocox使用的STM32库代码是cube库而不是std标准库,看来是紧跟ST的步伐那,还好之前也使用过cube库,更加方便了coocox的上手,在CoIDE上设置好编译器路径,这个在coocox的官网上有介绍,很简单。
创建好一个STM32F030C8T6的工程,在Repository页面上添加cmsis_core、STM32F030x8_CUBELIB组件,使用coocox必须要了解的一个概念是Components(组件),它把库,驱动,OS,启动代码等抽象为组件,使用时直接添加即可,同时在组件中也配有示例代码,本例创建了一个USART的工程,添加完组件后会在工程目录下产生一个components的目录,里面存放我们添加的组件文件,目前该工程为空工程,添加两个文件uart.c、uart.h文件,工程组织如下:
uart.c和uart.h文件是从之前学习cube库时使用的直接拷贝过来稍作修改即可,uart.c代码如下:
#include "UART.h" #include "stm32f0xx_hal_def.h" UART_HandleTypeDef uartHandle; uint8_t aRxBuffer[BUFFSIZE]; uint8_t aTxBuffer[BUFFSIZE]; struct uart uart_rev; void HAL_UART_MspInit(UART_HandleTypeDef *huart) { GPIO_InitTypeDef GPIO_InitStruct; /*##-1- Enable peripherals and GPIO Clocks #################################*/ /* Enable GPIO TX/RX clock */ USARTx_TX_GPIO_CLK_ENABLE(); USARTx_RX_GPIO_CLK_ENABLE(); /* Enable USART2 clock */ USARTx_CLK_ENABLE(); /*##-2- Configure peripheral GPIO ##########################################*/ /* UART TX GPIO pin configuration */ GPIO_InitStruct.Pin = USARTx_TX_PIN; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_HIGH; GPIO_InitStruct.Alternate = USARTx_TX_AF; HAL_GPIO_Init(USARTx_TX_GPIO_PORT, &GPIO_InitStruct); /* UART RX GPIO pin configuration */ GPIO_InitStruct.Pin = USARTx_RX_PIN; GPIO_InitStruct.Alternate = USARTx_RX_AF; HAL_GPIO_Init(USARTx_RX_GPIO_PORT, &GPIO_InitStruct); /*##-3- Configure the NVIC for UART ########################################*/ /* NVIC for USART2 */ HAL_NVIC_SetPriority(USARTx_IRQn, 0, 1); HAL_NVIC_EnableIRQ(USARTx_IRQn); } /** * @brief UART MSP De-Initialization * This function frees the hardware resources used in this example: * - Disable the Peripheral's clock * - Revert GPIO and NVIC configuration to their default state * @param huart: UART handle pointer * @retval None */ void HAL_UART_MspDeInit(UART_HandleTypeDef *huart) { /*##-1- Reset peripherals ##################################################*/ USARTx_FORCE_RESET(); USARTx_RELEASE_RESET(); /*##-2- Disable peripherals and GPIO Clocks #################################*/ /* Configure UART Tx as alternate function */ HAL_GPIO_DeInit(USARTx_TX_GPIO_PORT, USARTx_TX_PIN); /* Configure UART Rx as alternate function */ HAL_GPIO_DeInit(USARTx_RX_GPIO_PORT, USARTx_RX_PIN); /*##-3- Disable the NVIC for UART ##########################################*/ HAL_NVIC_DisableIRQ(USARTx_IRQn); } /********************************************************************** 函数:uart_init() 函数作用:串口初始化 参数: uint32_t BaudRate=========================串口波特率 返回值:无 上一版本:无 当前版本:1.0 作者: 最后修改时间:2015-04-02 说明: **********************************************************************/ void uart_init(uint32_t BaudRate) { uartHandle.Instance = USARTx; uartHandle.Init.BaudRate = BaudRate; uartHandle.Init.WordLength = UART_WORDLENGTH_8B; uartHandle.Init.StopBits = UART_STOPBITS_1; uartHandle.Init.Parity = UART_PARITY_NONE; uartHandle.Init.HwFlowCtl = UART_HWCONTROL_NONE; uartHandle.Init.Mode = UART_MODE_TX_RX; if(HAL_UART_Init(&uartHandle) != HAL_OK) { Error_Handler(); } uart_rev.front = aRxBuffer; uart_rev.rear = aRxBuffer; //两个指针指向相同的地址空间 if(HAL_UART_Receive_IT(&uartHandle,(uint8_t*)aRxBuffer,1) != HAL_OK) { Error_Handler(); } } void Error_Handler(void) { while(1) { } } /********************************************************************** 函数:uart_read() 函数作用:从接收缓冲区中读取数据 参数: uint8_t *fmt--------------------------------接收到的数据 uint16_t time_out---------------------------超时时间 返回值:0:读取到数据-1:没有读取到数据 上一版本:无 当前版本:1.0 作者: 最后修改时间:2015-04-08 说明: **********************************************************************/ int8_t uart_read(uint8_t *fmt, uint16_t time_out) { while(time_out) { if(uart_rev.front != uart_rev.rear) { //如果队首指针和队尾指针不同表明缓冲区中有数据还未收取 *fmt=*uart_rev.front; uart_rev.front++; if (uart_rev.front >= (aRxBuffer+BUFFSIZE)) uart_rev.front = aRxBuffer; return 0; } time_out--; } return (int8_t)-1; } /********************************************************************** 函数:uart_char() 函数作用:发送一个字节数据 参数: uint8_t *fmt--------------------------------接收到的数据 返回值: 上一版本:无 当前版本:1.0 作者: 最后修改时间:2015-04-08 说明: **********************************************************************/ void uart_char(uint8_t fmt) { uartHandle.Instance->TDR = fmt; while(!(uartHandle.Instance->ISR & USART_ISR_TXE)); } void uart_send(uint8_t *fmt, uint16_t len) { while(len) { uart_char(*fmt); fmt++; len--; } return ; } /*********************************************************************************** 函数:fputc(int ch, FILE *f) 功能:重载标准函数里面的输入输出函数 参数:无 版本:V0.0.0 作者: 备注: ************************************************************************************/ #if defined(UART_DEBUG) int fputc(int ch, FILE *f) { USARTx->TDR = ch; while(!(USARTx->ISR & USART_ISR_TXE)); return ch; } #endif /** * @brief UART error callbacks * @param UartHandle: UART handle * @note This example shows a simple way to report transfer error, and you can * add your own implementation. * @retval None */ void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart) { } /** * @brief Tx Transfer completed callback * @param UartHandle: UART handle. * @note This example shows a simple way to report end of IT Tx transfer, and * you can add your own implementation. * @retval None */ void HAL_UART_TxCpltCallback(UART_HandleTypeDef * huart) { } /** * @brief Rx Transfer completed callback * @param UartHandle: UART handle * @note This example shows a simple way to report end of IT Rx transfer, and * you can add your own implementation. * @retval None */ void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { /* Set transmission flag: trasfer complete*/ uart_rev.rear++; //更新rear指针 if(uart_rev.rear >= (aRxBuffer + BUFFSIZE)) uart_rev.rear = aRxBuffer; HAL_UART_Receive_IT(huart,uart_rev.rear,1); } /******************************************************************************/ /* STM32L0xx Peripherals Interrupt Handlers */ /* Add here the Interrupt Handler for the used peripheral(s) (PPP), for the */ /* available peripheral interrupt handler's name please refer to the startup */ /* file (startup_stm32l0xx.s). */ /******************************************************************************/ /** * @brief This function handles UART interrupt request. * @param None * @retval None * @Note This function is redefined in "main.h" and related to DMA stream * used for USART data transmission */ void USARTx_IRQHandler(void) { HAL_UART_IRQHandler(& uartHandle); }uart.h代码如下:
#ifndef __UART_H__ #define __UART_H__ #include "stm32f0xx_hal.h" #include "stm32f0xx_hal_def.h" #include "stm32f0xx_hal_uart.h" #define UART_DEBUG //#undef UART_DEBUG #ifdef UART_DEBUG #include <stdio.h> #include <stdarg.h> #endif struct uart { uint8_t *rear; //在中断函数中更改 uint8_t *front; //在主循环中更改 }; #define USARTx USART1 #define USARTx_CLK_ENABLE() __USART1_CLK_ENABLE() #define USARTx_RX_GPIO_CLK_ENABLE() __GPIOA_CLK_ENABLE() #define USARTx_TX_GPIO_CLK_ENABLE() __GPIOA_CLK_ENABLE() #define USARTx_FORCE_RESET() __USART1_FORCE_RESET() #define USARTx_RELEASE_RESET() __USART1_RELEASE_RESET() /* Definition for USARTx Pins */ #define USARTx_TX_PIN GPIO_PIN_9 #define USARTx_TX_GPIO_PORT GPIOA #define USARTx_TX_AF GPIO_AF1_USART1 #define USARTx_RX_PIN GPIO_PIN_10 #define USARTx_RX_GPIO_PORT GPIOA #define USARTx_RX_AF GPIO_AF1_USART1 /* Definition for USARTx's NVIC */ #define USARTx_IRQn USART1_IRQn #define USARTx_IRQHandler USART1_IRQHandler #define BUFFSIZE 500 void HAL_UART_MspInit(UART_HandleTypeDef * huart); void HAL_UART_MspDeInit(UART_HandleTypeDef * huart); void uart_init(uint32_t BaudRate); int8_t uart_read(uint8_t *fmt, uint16_t time_out); void uart_char(uint8_t fmt); void uart_send(uint8_t *fmt, uint16_t len); void Error_Handler(void); void USARTx_IRQHandler(void); #endif </span>主函数稍作修改即可,由于在uart中已经定义了Error_Handler()方法,因此把main.c中的删掉并添加uart的初始化代码,如下
<span style="font-size:14px;">/* Add your application code here */ uart_init(115200); /* Infinite loop */ while (1) { uart_send("1234567890\r\n",12); HAL_Delay(500); }编译并下载代码到目标板运行,结果如下:
运行正常。
串口正常以后,就在想在coocox中如何使用printf函数呢,即把printf函数重定向到串口上,刚好在coocox的组件中有一个组件为Retarget_printf,添加该组件到工程中,该组件中有一个printf.c文件,用户需要去实现PrintChar(char c)函数,我们把在uart.c文件中的fputc函数替换成PrintChar(char c)函数,如下:
#if defined(UART_DEBUG) void PrintChar(char c) { USARTx->TDR = c; while(!(USARTx->ISR & USART_ISR_TXE)); return; } #endif在主函数中使用printf来打印信息,编译后发现一个错误,提示impure_ptr重复定义,在coocox官网中也有人遇到说是因为使用了标准的系统启动文件,在配置选项中勾选不使用标准的系统启动文件,如下:
再次编译提示位定义_init,在main.c文件中添加一个空的_init()函数,编译通过,下载运行,发现没有换行,如下:
0x0A字符没有输出,不得不说printf.c文件实现还是有些小问题的,解决办法是把"\r\n"放在最前面即可
while (1) { printf("\r\n1234567890"); HAL_Delay(500); }此时输出的信息是正常的,同时我们也可以格式化输出字符或整型值,但目前printf.c文件不支持浮点型数据输出,可以查看printf.c文件如下:
这个问题,coocox官网上有说不使用printf.c文件而是使用C库实现。我想修改下printf.c文件应该也是可以的。输出整型值如下:
浮点数支持的话,自己动手修改printf.c文件貌似比较费时间,还是用C库吧,毕竟之前MDK都是用的C库也,在工程中移除Retarget_printf组件,添加C_library组件,里面有一个syscalls.c文件,提供给用户一个_write接口,由于在CoIDE中所有组件文件都是上锁的,因此我们在外部用文本编辑器修改syscalls.c文件的_write函数,把宏打开,如下
/*Low layer write(output) function*/ __attribute__ ((used)) int _write(int file, char *ptr, int len) { #if 1 //user code example int i; (void)file; for(i = 0; i < len; i++) { // UART_PutChar is user's basic output function UART_PutChar(*ptr++); } #endif return len; }用户需要实现UART_PutChar()方法,把之前uart.c文件中的PutChar()方法换个名字就行了。由于使用到了C库,因此在配置选项的Link页面勾选使用Nano C库,如下:
还要使能Print float选项,由于不再使用Retarget_printf组件,所以这里使用了标准的系统启动文件,同时把main.c文件中的_init()方法删掉了。
编辑主函数测试代码:
while (1) { printf("\r\n1234567890"); printf("\r\nvalue=%d,%X",100,100); printf("\r\nabc:%f",123.56); HAL_Delay(500); }下载到目标板,运行,测试正常