硬件:正点原子STM32F103ZET6
(一 )基础配置
1.必须配置:
①配置板子型号/封装:
②配置时钟:外部晶振
③配置时基:串行总线调试(否则只能下载一次)、系统滴答定时器
④配置时钟树:HCLK输入72MHZ主频,回车自动分配时钟树
⑤配置工程名/IDE:
⑥配置分离.c/.h文件:
好了,你可以右上角Generate Code生成一个没有任何功能的代码。
2.需求配置:
①配置定时器/定时器中断:
定时计算公式:
Tout = ((arr+1)*(psc+1))/Tclk ; Tclk:定时器的输入时钟频率(单位MHZ) ?Tout:定时器溢出时间(单位为us) ? .TIM_Period = arr; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?eg;4999(周期) ? .TIM_Prescaler = psc; ? ? ? ? ? ? ? ? ? ? ? ? ? ? eg:7199(预分频) ? Tout = ((4999+1)×(7199+1))/72 = 500000us = 500ms ??
? Tout = ((9999+1)×(7199+1))/72 = 500000us = 1s ??
②配置LED:使能GPIO输出
初始电平:高电平(由程序改动,低电平有效)
模式:推挽输出
引脚上拉:初始3.3V电平
设置标签:提高代码复用性
?
③配置蜂鸣器:使能GPIO输出
初始电平:低电平(由程序改动,高电平有效)
模式:推挽输出
引脚上拉:初始3.3V电平
设置标签:提高代码复用性
④配置按键中断:使能GPIO中断(如不使用中断控制则配置按键为GPIO_Input)
NVIC使能
GPIO模式:下降沿触发
引脚上拉:初始接3.3V高电平
??
⑤配置串口/串口中断:异步收发(选后右边自动使能引脚)
3.FreeRTOS配置:
①V1版本,V2有点问题
②不用Systick作为时基,选择另一定时器作为时基
④使能定时器:
创建定时器函数
(二)基础代码(以下程序都写在main.c)
注意:代码写在begin和end间,不然加引脚后重新用cubemx生成新代码,你写的代码会消失!
按键GPIO_Input法1:延时消抖
/* USER CODE BEGIN 3 */
if(HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin)==GPIO_PIN_RESET)
{
HAL_Delay(10);
if(HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin)==GPIO_PIN_RESET){
HAL_GPIO_WritePin(LED0_GPIO_Port,LED0_Pin,GPIO_PIN_RESET);
}
while(HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin)==GPIO_PIN_RESET);
}
/* USER CODE END 3 */
按键GPIO_Input法2:工业一般采用状态机消抖(延时方法CPU效率降低)
/* USER CODE BEGIN PTD */
typedef enum{
KEY_CHECK = 0,
KEY_COMFIRM,
KEY_RELEASE
}KEY_STATE;
/* USER CODE END PTD */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
KEY_STATE KeyState = KEY_CHECK;
uint8_t KeyFlag = 0;
/* USER CODE END PV */
/* USER CODE BEGIN 2 */
int carIN =0;
HAL_TIM_Base_Start_IT(&htim6);
/* USER CODE END 2 */
/* USER CODE BEGIN 3 */
if(KeyFlag ==1){
KeyFlag = 0;
HAL_GPIO_TogglePin(LED0_GPIO_Port,LED0_Pin);
}
}
/* USER CODE END 3 */
/* USER CODE BEGIN 4 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef * htim){
if(htim ->Instance == TIM6){
switch(KeyState){
case KEY_CHECK:{
if(HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin)== GPIO_PIN_RESET){
KeyState = KEY_COMFIRM;
}
break;
}
case KEY_COMFIRM:{
if(HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin)== GPIO_PIN_RESET){
KeyState = KEY_RELEASE;
KeyFlag =1;
}else{
KeyState = KEY_CHECK;
}
break;
}
case KEY_RELEASE:{
if(HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin)== GPIO_PIN_SET){
KeyState = KEY_CHECK;
}
break;
}
default: break;
}
}
}
/* USER CODE END 4 */
按键GPIO_Exit法1:中断回调函数里,按下KEY0后LED0亮灭
/* USER CODE BEGIN 4 */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){
if(GPIO_Pin == KEY0_Pin){
HAL_GPIO_TogglePin(LED0_GPIO_Port,LED0_Pin);
}
}
/* USER CODE END 4 */
按键中断GPIO_Exit法2:多个按键中断选择
/* USER CODE BEGIN 4 */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){
switch(GPIO_Pin){
case KEY0_Pin:{
HAL_GPIO_TogglePin(LED0_GPIO_Port,LED0_Pin);
break;
}
case KEY1_Pin:{
HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin);
break;
}
default: break;
}
}
/* USER CODE END 4 */
串口法1:不使用重定向
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
uint8_t Temp[10];
/* USER CODE END PM */
? /* USER CODE BEGIN 3 */
if(HAL_UART_Receive(&huart1,Temp,5,100)== HAL_OK){
HAL_UART_Transmit(&huart1,Temp,5,100);
}
}
/* USER CODE END 3 */
串口使用重定向注意:
1.printf的时候加fput重定向函数了吗?
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
return ch;
}
int fgetc(FILE *f)
{
uint8_t ch = 0;
HAL_UART_Receive(&huart1, &ch, 1, 0xffff);
return ch;
}
2.Keil的Micro 微库勾了吗?
3.#include "stdio.h"加了吗?
串口法2:使用重定向
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stdio.h"
/* USER CODE END Includes */
/* USER CODE BEGIN 2 */
printf("INPUT:\r\n");
char RecData;
/* USER CODE END 2 */
/* USER CODE BEGIN 3 */
scanf("%c",&RecData);
if(RecData == 'y')
{
printf("Receive y\r\n");
}else{
printf("Receive others\r\n");
}
}
/* USER CODE END 3 */
/* USER CODE BEGIN 4 */
int fputc(int ch,FILE*f){
HAL_UART_Transmit(&huart1,(uint8_t*)&ch,1,HAL_MAX_DELAY);
return ch;
}
int fgetc(FILE*f){
uint8_t ch;
HAL_UART_Receive(&huart1,(uint8_t*)&ch,1,HAL_MAX_DELAY);
return ch;
}
/* USER CODE END 4 */
串口法3:使用scanf
/* USER CODE BEGIN 2 */
printf("INPUT:\r\n");
/* USER CODE END 2 */
/* USER CODE BEGIN 3 */
? ? char str[10];
? ? printf("请输入字符串:");
? ? scanf("%s",str);
? ? printf("输出结果:%s\r\n",str);
}
/* USER CODE END 3 */
串口法4:使用条件编译,方便串口调试时设置1打log,出产品时设置0
/* USER CODE BEGIN PD */
#define Log 1
/* USER CODE END PD */
/* USER CODE BEGIN 3 */
#if Log
printf("stm32");
#endif
}
/* USER CODE END 3 */
串口法5:使用格式化条件编译,区分info、debug、error时log
/* USER CODE BEGIN Includes */
#include "stdio.h"
#define USER_MAIN_DEBUG //define or annotation
?
#ifdef USER_MAIN_DEBUG
#define user_main_printf(format, ...) printf(format "\r\n",##__VA_ARGS__)
#define user_main_info(format, ...) printf("[main]info:"format "\r\n",##__VA_ARGS__)
#define user_main_debug(format, ...) printf("[main]debug:"format "\r\n",##__VA_ARGS__)
#define user_main_error(format, ...) printf("[main]error:" format "\r\n",##__VA_ARGS__)
#else
#define user_main_printf(format, ...)
#define user_main_info(format, ...)
#define user_main_debug(format, ...)
#define user_main_error(format, ...)
#endif
/* USER CODE END Includes */
? /* USER CODE BEGIN 3 */
user_main_info("hello stm32");
}
/* USER CODE END 3 */
(三)FreeRTOS代码(以下程序都写在freertos.c)
定时器例1:(usart.c加fputc勾微库)
#include "stdio.h"
/* USER CODE BEGIN RTOS_TIMERS */
/* start timers, add new ones, ... */
osTimerStart(myTimer01Handle,1000);//1秒钟启动一次定时
/* USER CODE END RTOS_TIMERS */
/* Callback01 function */
void Callback01(void const * argument)
{
/* USER CODE BEGIN Callback01 */
static int32_t count = 0;
printf( "定时器计数:%d.\r\n",count++);
/* USER CODE END Callback01 */
}
定时器例2:(usart.c加fputc勾微库)
/* USER CODE BEGIN RTOS_TIMERS */
/* start timers, add new ones, ... */
osTimerStart(myTimer01Handle,1000);//1秒钟启动一次定时
/* USER CODE END RTOS_TIMERS */
/* Callback01 function */
void Callback01(void const * argument)
{
/* USER CODE BEGIN Callback01 */
HAL_GPIO_TogglePin(LED0_GPIO_Port,LED0_Pin);
/* USER CODE END Callback01 */
}
消息队列:打印hello(加fputc)
1.创建两个任务:用于数据接送和发送
2.一般不用cubemx生成消息队列:有点问题,自己写程序
/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN FunctionPrototypes */
QueueHandle_t DataQueue;
/* USER CODE END FunctionPrototypes */
/* USER CODE BEGIN RTOS_QUEUES */
/* add queues, ... */
DataQueue = xQueueCreate(2,9);
/* USER CODE END RTOS_QUEUES */
void DataSendTask(void const * argument)
{
/* USER CODE BEGIN DataSendTask */
uint8_t buf[9] = "hello\r\n";
/* Infinite loop */
for(;;)
{
HAL_GPIO_TogglePin(LED0_GPIO_Port,LED0_Pin);
xQueueSend(DataQueue,buf,10);
? osDelay(1);
}
/* USER CODE END DataSendTask */
void DataReceiveTask(void const * argument)
{
/* USER CODE BEGIN DataReceiveTask */
uint8_t buf[9];
/* Infinite loop */
for(;;)
{
if(pdPASS == xQueueReceive(DataQueue,buf,10)){
printf(buf);
}
? osDelay(1);
}
中断
/* Private application code --------------------------------------------------*/
/* USER CODE BEGIN Application */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){
?
}
/* USER CODE END Application */
任务通知:按键0翻转LED0
/* USER CODE END Header_StartLED2Task */
void StartLED2Task(void const * argument)
{
/* USER CODE BEGIN StartLED2Task */
static uint8_t count =0;
uint32_t NotifyValue;
BaseType_t err;
/* Infinite loop */
for(;;)
{
err = xTaskNotifyWait(0x00,0xFFFFFFF,&NotifyValue,portMAX_DELAY);
if(err == pdPASS){
if((NotifyValue&0x01)!=0){
if(count == 1){
HAL_GPIO_WritePin(LED0_GPIO_Port,LED0_Pin,GPIO_PIN_RESET);
count =0;
}
else{
HAL_GPIO_WritePin(LED0_GPIO_Port,LED0_Pin,GPIO_PIN_SET);
count =1;
}
}
}
}
/* USER CODE END StartLED2Task */
}
/* USER CODE BEGIN Application */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){
BaseType_t YieldRequired;
if(GPIO_Pin == KEY0_Pin){
xTaskNotifyFromISR(LED2TaskHandle,0x01,eSetBits,&YieldRequired);
portYIELD_FROM_ISR(YieldRequired);
}
}
/* USER CODE END Application */
任务挂起恢复:亮两次挂起按键0恢复LED
/* USER CODE END Header_StartLED2Task */
void StartLED2Task(void const * argument)
{
/* USER CODE BEGIN StartLED2Task */
static uint8_t count =0;
/* Infinite loop */
for(;;)
{
HAL_GPIO_TogglePin(LED0_GPIO_Port,LED0_Pin);
? osDelay(300);
count++;
if(count>3){
count =0;
vTaskSuspend(NULL);
}
}
/* USER CODE END StartLED2Task */
}
/* USER CODE BEGIN Application */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){
BaseType_t YieldRequired;
if(GPIO_Pin == KEY0_Pin){
YieldRequired = xTaskResumeFromISR(LED2TaskHandle);
if(YieldRequired == pdTRUE){
portYIELD_FROM_ISR(YieldRequired);
}
}
}
/* USER CODE END Application */
|