本项目使用STM32作为主控芯片,通过PWM分别对红绿蓝三个LED进行调光达到对RGB颜色的控制。可以以渐变的方式实现对灯光的控制。也就是常说的1600万色RGB灯。
本次项目使用通过ST官方的STM32CubeMX工具生成初始化代码,使用ST官方的TrueStudio工具进行开发介绍。
需要准备的材料有:
1、STM32F410RB-NUCLEO开发板
2、USB MINI线一根
需要准备的软件有:
1、STM32CubeMX软件(下载链接,需要使用注册ST账号下载)
2、TrueStudio软件(下载链接)
另外需要板卡的原理图和STM32F4 HAL库的也可以从这里下载。
下面分别介绍一下板卡和软件。
STM32F410RB-NUCLEO开发板板载STM32F410RBT6芯片,STM32F410RBT6芯片是一款基于ARM Cortex-M4的MCU,高达100MHZ主频,拥有32KB RAM,128KB FLASH,3个 I2C,3个USART,3个SPI/I2S,9个timer,50个IO,LQFP64封装。
STM32CubeMX是基于eclipse 的一个插件,用来对STM32产品的配置及初始化代码的生成。使用STM32CubeMX来生成初始化代码时,甚至可以无视芯片数据手册,直接在STM32CubeMX上进行图形化配置,免去了以往繁琐的初始化代码的编写过程。
TrueStudio for STM32是ST官方收购Atollic后发布的一款基于Eclipse的C / C++集成开发工具。是一个灵活的、可扩展的IDE和调试STM32单片机的强大工具。以往流行的Keil MDK、IAR收拾收费的,而TrueStudio 是完全免费的。其拥有的很多强大的开发和调试功能完全不亚于Keil MDK、IAR。将会是未来开发STM32的主流工具。
接下来开始进入正题,使用软件来生成初始化代码,完成一个LED闪烁功能。
以Windows 10为例,安装好所需软件后,首先将板卡通过USB连接PC,板卡右上角STLINK的LED灯是红色常亮状态,如果是闪亮状态,可能是STLINK驱动没有正常安装,TrueStudio在安装时一般会自带STLINK驱动。
打开STM32CubeMX,菜单栏选择Help->Embedded Sofeware and embeded sofeware packs releases,然后选择并且下载最新版版本的STM32F4 HAL库。也可以手动从ST官方手动下载的STM32F4 HAL库,通过Help->Install Path导入。完成后选择主界面的New Project选择STM32F410RBT6芯片,然后可以进行初始化代码配置了。
这里根据原理图,在Pinout界面配置外部RCC HSE晶振为8MHZ,USARTS2为调试串口,PA5推挽输出驱动板载的贴片LED灯,PC13为按键外部中断,PA8、PA9、PA10分别为timer1的PWM CH1、PWM CH2、PWM CH3通道。同时勾选FREERTOS Enabled,使用FreeRTOS。
在Clock Configuration界面修改HSE的频率为8MHZ,NUCLEO板卡上MCU和STLINK共享同一个HSE晶振,修改CPU主频HCLK为100MHZ。
最后在Configuration界面对各个启用的外设进行详细配置,IO输出模式,中断使能,DMA使能,定时器分频和重装载配置等。
配置完了之后就可以在菜单栏的Project->Generate Code中生成代码了,生成填写项目名称,IDE选择TrueStudio,其他默认。
接下来使用TrueStudio打开工程,生成的工程已经完成了各个外设的初始化代码,无需手动编写。在工程生成的代码文件中编写自己的代码时要注意,需要在USER CODEBEGIN x和USER CODE ENDX注释中间加入,否则在下一次生成代码时,自己编写的代码会被覆盖。
由于串口调试需要使用printf,所以需要加入串口打印功能的代码。复制粘贴下面的代码到/* USER CODE BEGIN 0 */和/* USER CODE END 0 */中间。
/* USER CODE BEGIN 0 */ #ifdef __GNUC__ #define PUTCHAR_PROTOTYPE int __io_putchar(int ch) PUTCHAR_PROTOTYPE { HAL_UART_Transmit(&huart2, (uint8_t*)&ch, 1, HAL_MAX_DELAY); return ch; } #endif int _write(int file, char *ptr, int len) { int DataIdx; for (DataIdx = 0; DataIdx < len; DataIdx++) { __io_putchar(*ptr++); } return len; } /* USER CODE END 0 */
main函数中进行的对HAL库和时钟、外设初始化,然后是FreeRTOS的相关代码。由于ST官方在STM32CubeMX生成的工程中,添加OS适配层进行OS API的适配,所以在main.c中看到的OS相关代码不像FreeRTOS的API。
int main(void) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /* MCU Configuration----------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_DMA_Init(); MX_USART2_UART_Init(); MX_TIM1_Init(); /* USER CODE BEGIN 2 */ /* USER CODE END 2 */ /* USER CODE BEGIN RTOS_MUTEX */ /* add mutexes, ... */ /* USER CODE END RTOS_MUTEX */ /* USER CODE BEGIN RTOS_SEMAPHORES */ /* add semaphores, ... */ /* USER CODE END RTOS_SEMAPHORES */ /* USER CODE BEGIN RTOS_TIMERS */ /* start timers, add new ones, ... */ /* USER CODE END RTOS_TIMERS */ /* Create the thread(s) */ /* definition and creation of defaultTask */ osThreadDef(defaultTask, StartDefaultTask, osPriorityNormal, 0, 128); defaultTaskHandle = osThreadCreate(osThread(defaultTask), NULL); /* USER CODE BEGIN RTOS_THREADS */ /* add threads, ... */ /* USER CODE END RTOS_THREADS */ /* USER CODE BEGIN RTOS_QUEUES */ /* add queues, ... */ /* USER CODE END RTOS_QUEUES */ /* Start scheduler */ osKernelStart(); /* We should never get here as control is now taken by the scheduler */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ }
其中宏osThreadDef用于创建osThreadDef_t变量,这是一个描述线程信息的结构体。
函数osThreadCreate用于根据osThreadDef_t变量创建线程。
函数osKernelStart用于启动OS内核。main函数会在这里进行内核调度,后面的代码将不会被运行。应用层的代码可以在StartDefaultTask函数中运行,这是启动内核后的第一个线程。
在for循环中添加代码,让LED灯闪烁,串口打印LED blink。
void StartDefaultTask(void const * argument) { /* USER CODE BEGIN 5 */ /* Infinite loop */ for(;;) { HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5); printf("LED blink\r\n"); osDelay(500); } /* USER CODE END 5 */ }
然后选择工具栏的第一个小锤子编译,第一个小虫子进行调试。
编译成功控制台会输出以下日志。
进入调试界面后,按工具栏的继续按钮或者F8启动代码,可以看到LED每500ms闪烁一次。
在菜单栏的查看->终端可以开启串口终端,终端中点击第一个图标可以配置和启动串口,启动后可以看到串口不断输出LED blink。
到这里就完成了第一个工程。后面的项目代码都是基于这个工程进行开发的。