蓝桥杯准备---练习日志

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中模块化的感觉。可以画图,做流程图将要做的事情分开规划好

 

  代码就不补充了,写的也一般。

 

posted @   (喜欢黑夜的孩子)  阅读(18)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示