串口发送与接收

最近刚学ucos-II,想利用ucos-ii中的任务调度来实现数据包处理功能,数据包采用stm32串口收发。具体思路如下:

1、用串口1发送数据包,串口2接收。
2、滴答定时器判接收超时。
3、接收超时则进入数据处理任务。

先写串口部分。
发送数据包函数:

void USART1_Send_Message(u8 *SendData,u8 len)
{
  while(len--)
   {
     USART_SendData(USART1,*SendData++);
     while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET)
   }
}

串口2接收中断:

u8 *RES;
void USART2_IRQHandler(void)
{
     if(USART_GetITStatus(USART2,USART_IT_RXNE))
     {
      *RES= USART_ReceiveData(USART2); 
      }
}

开始调试,断点打在中断函数第一个括号,发现进不了,查了半天才发现问题出在
这里写图片描述
错在时钟使能上,导致USART2无法接收数据。 改正后,断点打在中断能进去,但是运行完报硬件错误中断,把U8* res放进中断函数后,好了。原因不值,估计涉及野指针,明天补充。。。
接昨天内容,在能接受到字节数据后,断点打在接收中断函数,发现会漏数据,一开始以为是时钟或者中断优先级问题,后来将断点打在串口发送函数中,漏字节现象消失。

由于在具体项目中,串口接收中断基本不回去直接处理字节数据,而是等缓冲区满了之后再将数据存入内存。因此中断要修改成接收不定长数据包形式。

串口部分修改后如下:

void USART1_Send_Message(u8 *SendData,u8 len)
{
  while(len--)
  {  
      USART_ClearFlag(USART1, USART_FLAG_TC);
      USART_SendData(USART1, *SendData++);
      while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
  }
    return;
}

void USART2_IRQHandler(void)
{
 u8 res;
 static u8 first_byte=0;         
 static u8 which_buff=0;          

 if(USART_GetITStatus(USART2,USART_IT_RXNE)) 
     {   
     switch(first_byte)               //接收到首字符
     {
     case  0:                          
                res= (u8)USART_ReceiveData(USART2);
                if(res==0x7A)        //首字符为0x7A     
                    {                             
                    if_start_systick=1;  //进入滴答定时器中断    
                    first_buff[usart_RecIndex++]=res;  
                    first_byte=1;      //非首字符标志     
                    data_comed=1;     //新数据标志,滴答定时器中断计数值清零     
                    return;
                    }
               break; 
     case  1:                    //接收到非首字符           
           data_comed=1;         //新数据标志,滴答定时器中断计数值清      
           if(USART_GetFlagStatus(USART2, USART_FLAG_ORE) != RESET)  
                 {
                    (void)USART_ReceiveData(USART2);//溢出
                    return;
                 }
          else
                 {
                switch(which_buff)  //选择接收数据存放数组          
                   {
                    case first_buff_flag:         
                    if(usart_RecIndex >= BUF_SIZE)//第一个数组满  
                        {
                        which_buff=second_buff_flag; 
                        OSSemPost(sem_dpacket);//申请信号量,进入任务处理
                        usart_RecIndex=0;    //字符位置清零
                        second_buff[usart_RecIndex++]=(u8)USART_ReceiveData(USART2);
                        }
                    else
                        {
                        first_buff[usart_RecIndex++]=(u8)USART_ReceiveData(USART2);
                        }
                    break;

                    case second_buff_flag:   //第二个数组
                    if(usart_RecIndex >= BUF_SIZE)//第二个数组满
                        {
                        which_buff=first_buff_flag;
                        OSSemPost(sem_dpacket);
                        usart_RecIndex=0;
                        first_buff[usart_RecIndex++]=(u8)USART_ReceiveData(USART2);
                        }
                        else
                        {
                        second_buff[usart_RecIndex++]=(u8)USART_ReceiveData(USART2);
                        }
                        break;

                        default :break;
                        }
                    }   
                break;
                default : break;
                }
          }
     }

滴答定时器判超时:

void SysTick_Handler(void)
{   
    static u8 tim_cnt=0;     //中断计数器
    if(delay_osrunning==1)                      
    {

        OSIntEnter();                           //½øÈëÖжÏ
        OSTimeTick();                           //µ÷ÓÃucosµÄʱÖÓ·þÎñ³ÌÐò      
        if(if_start_systick) //若接收到有效数据 
        {   
            if(tim_cnt>=30)   //无数据时长达到30x5=150ms,认为此次接收完成
            {
                tim_cnt=0;
                if_start_systick=0; 
                OSSemPost(sem_dpacket);  //进入任务处理        
            }
            else
            {
                if(data_comed==1)   //5ms内有新数据
                {
                    tim_cnt=0;      //计数器清零
                    data_comed=0;   //标志清零
                }
                else
                {
                    tim_cnt++;   //5ms内无新数据
                }
            }
      }
        OSIntExit();            
    }

    return;
}

任务处理函数处理数据包:

//此任务未做数据处理,简单将接受数组中的数据取出并在LCD显示
void dpacket_task(void *pdata)
{ 
    u8 err;
    u8 i;
    u8 x_loc;
     while(1)
    {
        OSSemPend(sem_dpacket,0,&err);
        if(usart_RecIndex==sizeof(buf))
        {
       memcpy(packetdata,first_buff,usart_RecIndex);
             for(i=0;i<=usart_RecIndex-1;i++)
             {
                 x_loc=20*i+10;
                 LCD_ShowxNum(x_loc,140,(u16)first_buff[i],3,16,1);
             }          
        }       
    }           
}

注:此任务没有长数据包进行验证。

  • 6
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
串口通信是通过串口发送接收数据来进行通信的。在串口通信中,一般使用UART通信协议,其数据传输的速率、数据位数、校验位和停止位等参数需要保持一致才能正确通信。 在C/C++中,可以使用串口库函数来实现串口通信。常用的串口库函数包括: 1. 打开串口:使用open()函数打开串口设备文件,例如:open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY); 2. 配置串口参数:使用tcgetattr()函数获取当前串口参数,然后使用cfsetispeed()和cfsetospeed()函数设置串口的波特率,使用tcsetattr()函数将设置好的参数写入串口,例如: ```c++ struct termios options; tcgetattr(fd, &options); cfsetispeed(&options, B9600); cfsetospeed(&options, B9600); options.c_cflag |= (CLOCAL | CREAD); options.c_cflag &= ~PARENB; options.c_cflag &= ~CSTOPB; options.c_cflag &= ~CSIZE; options.c_cflag |= CS8; options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); options.c_oflag &= ~OPOST; tcsetattr(fd, TCSANOW, &options); ``` 3. 发送数据:使用write()函数向串口写入数据,例如:write(fd, "Hello world", strlen("Hello world")); 4. 接收数据:使用read()函数从串口读取数据,例如:read(fd, buf, sizeof(buf)); 5. 关闭串口:使用close()函数关闭串口设备文件,例如:close(fd); 需要注意的是,在实际应用中,由于串口通信存在一定的数据丢失和接收错误的可能性,需要对数据进行校验和重传等处理,以保证通信的可靠性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值