蓝桥杯准备---练习日志
2024-01-17
利用Cubemx配置usart中Asyn... 和 Syn....的意思是什么?
使用串口时报错如下 ------解决办法:添加st官方提供的串口驱动文件
修改底层printf内部的fputs代码 ---实现printf函数通过串口输出,需要利用LIB什么的......
我猜测这个函数是向某个文件流中写入一个字符,printf会调用这函数来向标准输出文件流写入字符(本来是),不过这里被改写为向usart发送了,所以..printf被重定向了。
int fputc(int c, FILE *stream) { HAL_UART_Transmit(&huart1,(u8 *)&c,1,10); return c; }
中断接收回调函数处理 ---每输入一个字符触发一次中断。如当串口助手中输入12345相当于进入了5次中断,这5次中断中Rx_Dat的值分别未‘1’‘2’‘3’‘4’‘5’,利用Rx_Data存储接下来的值
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if(huart->Instance==USART1) { Rx_Data[Rx_Count] = Rx_Dat; Rx_Count++; HAL_UART_Transmit(&huart1,&Rx_Dat,1,1); HAL_UART_Receive_IT(&huart1,&Rx_Dat,1); } if(Rx_Count == 10) HAL_UART_Transmit(&huart1,Rx_Data,10,1); }
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if(huart->Instance==USART1) { rx_data[rx_count] = rx_temp; rx_count++; HAL_UART_Receive_IT(&huart1,&rx_temp,1); } if(rx_temp == '\n') // 固定接收显示 { printf("接收到数据为:%s\r\n",rx_data); //printf()受到\r\n的影响而打印不出来断续的数据 //HAL_UART_Transmit(&huart1,rx_data,10,1); memset(rx_data,0,sizeof(rx_data)); rx_count = 0; } }
串口中断回调函数中重新接收不能太快执行不然会干扰原来的数据...........
内存拷贝函数memcpy有方向性,别弄错了,而且串口接收到的数据最好放到一个静态变量中,防止后续变量输入干扰到
第12届蓝桥杯嵌入式习题练习
LED部分
由于部分引脚的和LCD重用,所以这里使用了锁存器,由LE来控制锁存器的使能,低电平有效。每次修改LED的控制需要调用一次下面的函数
HAL_GPIO_WritePin(LED_CMD_GPIO_Port, LED_CMD_Pin, GPIO_PIN_SET);
HAL_GPIO_WritePin(LED_CMD_GPIO_Port, LED_CMD_Pin, GPIO_PIN_RESET);
按键采集部分
uint8_t __BSP_Key_get() { uint8_t temp = 0; if(HAL_GPIO_ReadPin(Button4_GPIO_Port,Button4_Pin) == 0 ) temp = KEY4; if(HAL_GPIO_ReadPin(Button3_GPIO_Port,Button3_Pin) == 0 ) temp = KEY3; if(HAL_GPIO_ReadPin(Button2_GPIO_Port,Button2_Pin) == 0 ) temp = KEY2; if(HAL_GPIO_ReadPin(Button1_GPIO_Port,Button1_Pin) == 0 ) temp = KEY1; return temp; } //采集按键值 uint8_t BSP_Key_get() { uint8_t Key_num = 0; uint8_t Old_Key_num = 0; uint8_t Key_value = 0; Key_num = __BSP_Key_get(); //采集按下的按键值
//防止按键抖动的操作 Key_value = Key_num & (Key_num ^ Old_Key_num); Old_Key_num = Key_num; return Key_value; }
LCD部分
官方提供了一个LCD显示库来显示
LCD_Init();
LCD_Clear(Black); //清屏
LCD_SetTextColor(White); //设置字体颜色
LCD_SetBackColor(Black); //设置背景颜色
sprintf(LCD_Content," CNBR:%d ",CNBR);
LCD_DisplayStringLine(Line4,LCD_Content); //输出LCD_content中的内容
其它配置
LCD_Disp ^=0x1;
对LCD_Disp每次执行会在0,1之间循环数据变化
串口配置
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if(huart->Instance==USART1) { Rx_Data[Rx_Count++]=Rx_Dat; } if(Rx_Count == 22) { Rx_flag = 1; printf("%s\r\n",Rx_Data); } //再次执行串口接收中断会干扰原来的数据,必须放在最末尾,数据最好另外保存 HAL_UART_Receive_IT(&huart1,&Rx_Dat,1); //执行该函数则输入一个字符就进一次中断 }
在需要的时候自写一个字符串比较和拷贝函数会比使用memcpy/strncpy来的方便
uint8_t str_copy( void * source, void *destination,uint8_t n) { char *p1 = (char *)source; char *p2 = (char *)destination; uint8_t i =0; for( i =0;i<n;i++) { p2[i] = p1[i]; } p2[i] = '\0'; //最后必须补充‘\0’ return 0; } //字符串比较 uint8_t str_cmp( void * str1, void *str2,uint8_t n) { char *p1 = (char *)str1; char *p2 = (char *)str2; for(uint8_t i =0;i<n;i++) { if(p1[i] != p2[i]) return 0xff; } return 0; }
关于strncpy和memcpy
int main() { char src[40]; char dest[12]; memset(dest, '\0', sizeof(dest)); strcpy(src, "This is 2xkt.com"); strncpy(dest, src, 10); printf("最终的目标字符串: %s\n", dest); return(0); }
会从目标地址处复制n个字符到新地址中并自动补0.
相比较之下,memcpy则能应用于非字符的数组类型
串口的数据到来很适合利用状态机来处理分析数据的格式,内容等是否有错,条理狠清晰
void BSP_usart_proj() { static uint8_t data_state = 0; //接收到完整数据 if(Rx_flag) { Rx_flag = 0; printf("数据输入正确\r\n"); data_state = 1; #ifdef USART_DEBUG printf("当前state : %d\r\n",data_state); printf("串口收到数据:%s\r\n",Rx_Data); #endif } //检测数据格式 else if( data_state==1 ) { if(usart_Type() == 1) { data_state = 2; #ifdef USART_DEBUG printf("数据格式正确\r\n"); printf("当前state : %d\r\n",data_state); #endif } else { printf("ERROR:数据格式出现问题"); data_state = 0; Rx_Count = 0; } } //检测数据内容 else if( data_state == 2) { if(usart_content() == 1) { data_state = 3; #ifdef USART_DEBUG printf("数据内容正确\r\n"); printf("当前state : %d\r\n",data_state); #endif } else { printf("ERROR:数据内容出现问题"); data_state = 0; Rx_Count = 0; } } //检测完毕,开始输出 else if( data_state == 3) { usart_data_proj(); data_state = 0; Rx_Count = 0; } }
整体做下来的感觉
1. DEBUG测试代码能写就写,不要嫌麻烦,不然后面找DEBUG有的是时间给你麻烦的...........
#ifdef USART_DEBUG printf("数据内容正确\r\n"); printf("当前state : %d\r\n",data_state); #endif
2. 写代码前最好将各模块都规划好再写,尤其是各模块之间的联系,其实就是FPGA中模块化的感觉。可以画图,做流程图将要做的事情分开规划好
代码就不补充了,写的也一般。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律