[总线]UART串口通信

UART:

UART:Universal Asynchronous Receiver/Transmitter,通用异步接收/发送装置

异步

不知道数据什么时候来

接线

TX
RX
TX
RX
SOC
电平转换模块
PC

SOC和PC等设备都是TTL电平
0V 为 0
3.3V/5V为1
电平转换模块的作用:
因为串口用于远距离通信,会影响到电路的电压,如果还是如上面这样采用TTL电平, 就会出现问题;
以下是常用的两种总线:
R232总线
距离25米以内,全双工;每根线,大小在正负3-15V之间
R485总线
距离1200米,半双工;通过两根线的电压差表示大小

如何发送数据

  1. 信号协议(数据位、停止位、奇偶校验)
  2. 一定时序(波特率)
  3. 首先进行电平的装换,通知接收设备准备接收数据

一些经验之谈

  1. 串口接收,采用中断,尽量不在中断里处理数据,最好用一个大的队列来保存接收的数据,如果硬件支持就用硬件的,否则就自己搭一个软件FIFO;
  2. 串口发送,根据需求选择是否采用中断,如果采用中断,就像上面一样采用队列存储数据,依次发送;
    如果直接发送,需要确保在发送过程中,不被打断/抢占,导致发送丢包,或者出错(如,前面发送010203040506,发送了010203,然后中断发送070809101112;实际发送就是010203-070809101112-040506)

FIFO

uart.h
//缓存最大值,最多一次性可接收的字节数
#define UART_QUEUE_MAX_SIZE              80
//数据帧起始或结束数据
#define UART_QUEUE_START_DATA         0XAA
#define UART_QUEUE_END_DATA         0X55
#define UART_QUEUE_START_LENGHT         0X10
//数据帧长度
#define UART_QUEUE_DATA_FRAME_LENGTH     6

typedef struct uart_cmd_queue_
{
    unsigned int head;                               // 队列FIFO头
    unsigned int tail;                               // 队列FIFO尾
    unsigned char  dat[HMI_QUEUE_MAX_SIZE];            // 数据缓存区
}UART_CMD_QUEUE_STRUCT;

uart.c
/* 队列FIFO */
UART_CMD_QUEUE_STRUCT m_que;


/**
  * @brief      串口接收队列复位
  * @param      None
  * @retval     None
  */
void Uart_Queue_Reset(void)
{
    m_que.head = 0;
    m_que.tail = 0;
}

/**
  * @brief      存入一个数据到串口接收队列(FIFO)中
  * @param      存入的数据
  * @retval     None
  */
void Uart_Queue_Push(unsigned char l_dat)
{
    unsigned int pos;

    pos  = (m_que.tail + 1) % UART_QUEUE_MAX_SIZE;
    /*非满状态*/
    if(pos != m_que.head)
    {
        m_que.dat[m_que.tail] = l_dat;
        m_que.tail = pos;
    }
}


/**
  * @brief      从串口接收队列(FIFO)中取出一个字节数据
  * @param      取出的数据
  * @retval     None
  */
void Uart_Queue_Pop(unsigned char *l_dat)
{
    unsigned int i;

    /*非空状态*/
    if(m_que.head != m_que.tail)
    {
        i = m_que.head;
        *l_dat = m_que.dat[i];
        m_que.head = (m_que.head+1) % UART_QUEUE_MAX_SIZE;
    }
}


/**
  * @brief      获取串口接收队列(FIFO)的长度
  * @param      None
  * @retval     接收队列(FIFO)的长度
  */
unsigned int Uart_Queue_Size(void)
{
    return ((m_que.tail + UART_QUEUE_MAX_SIZE - m_que.head) % UART_QUEUE_MAX_SIZE);
}

/**
  * @brief      找出完整一帧指令
  * @param      完整一帧指令
  * @param      缓存区大小
  * @retval     完整指令长度
  */
unsigned int Uart_Queue_Find_Cmd(unsigned char *buf)
{

    unsigned int cmd_size = 0;
    unsigned char l_dat = 0;
    /* 队列指针 */
    static unsigned int m_cmd_pos = 0;
    /*取一个数据*/
    Hmi_Queue_Pop(&l_dat);
    switch(m_cmd_pos)
    {
        case 0:
        {
            /*长度出错,跳过*/
            if(l_dat != UART_QUEUE_START_DATA)
            {
                m_cmd_pos = 0;
                continue;
            }
            buf[m_cmd_pos] = l_dat;
            m_cmd_pos = 1;
            break;
        }
        default:
        {
            if(m_cmd_pos < UART_QUEUE_DATA_FRAME_LENGTH)
            {
                buf[m_cmd_pos] = l_dat;
            }
            else
            {
                /*得到完整的帧尾*/
                cmd_size = m_cmd_pos;
                m_cmd_pos = 0;

                if(l_dat == UART_QUEUE_END_DATA)
                {
                    return cmd_size;
                }
            }
            m_cmd_pos++;

            break;
        }
    }
    return 0; //没有形成完整的一帧
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值