PK 使人进步:晒晒你的串口程序

[复制链接]
11729|61
Periodic 发表于 2011-11-11 19:54 | 显示全部楼层
程序匠人 发表于 2011-11-11 20:10 | 显示全部楼层
哈哈,又见pk
haitao10086 发表于 2011-11-11 22:52 | 显示全部楼层
lgnativs 发表于 2011-11-12 09:40 | 显示全部楼层
#include "hal_uart.h"

static uint uart_rx_cnt = 0;
static uint uart_tx_cnt = 0;
uint uart_rx_len;
uint uart_tx_len;
byte * uart_rx_ptr;
byte * uart_tx_ptr;
byte uart_rx_completed;
byte uart_tx_completed;

CALLBACKFUNC pHandleReceive;

static void uart0_isr(void) interrupt
INTERRUPT_UART0
{
  if(RI0 == 1)
  {
    RI0 = 0;
    if (uart_rx_cnt < uart_rx_len)
    {
      *(uart_rx_ptr + uart_rx_cnt) = SBUF0;
      uart_rx_cnt++;
      if(uart_rx_cnt ==
uart_rx_len)

uart_rx_completed = 1;
    }
    if(pHandleReceive != 0)
    {

(*pHandleReceive)(SBUF0);
    }
  }
  if(TI0 == 1)
  {
    TI0 = 0;

uart_tx_cnt++;

if(uart_tx_cnt >= uart_tx_len)

uart_tx_completed = 1;

else
    {
      SBUF0 = *(uart_tx_ptr + uart_tx_cnt);
    }
  }
}


void hal_uart_init(BAUD_RATE baud)
{

XBR0 |= 0x01;
//UART0 Tx-P0.4,Rx-P0.5

P0MDOUT |= 0x10;
//Tx as Push-Pull

ES0 = 0;                      // Disable UART0 interrupt while initializing

uart_rx_len = 0;

uart_tx_len = 0;

uart_rx_completed = 0;

uart_tx_completed = 0;

pHandleReceive = 0;
  switch(baud)
  {
    case BAUD_9600:

    TMOD      = 0x20;
// 8位重装载模式

    CKCON     = 0x00;
// T1分频系数

    TH1       = 0x30;
// 定时器重装载值
      break;
    case BAUD_14400:

    TMOD      = 0x20;

    CKCON     = 0x00;

    TH1       = 0x75;


break;

case BAUD_19200:

    TMOD      = 0x20;

    CKCON     = 0x00;

    TH1       = 0x98;

break;

case BAUD_57600:

TMOD      = 0x20;

    CKCON     = 0x01;

    TH1       = 0x98;

break;

case BAUD_115200:

    TMOD      = 0x20;

    CKCON     = 0x08;

    TH1       = 0x30;


break;

    default:

    TMOD      = 0x20;

    CKCON     = 0x00;

    TH1       = 0x30;
      break;
  }

SCON0 = 0x10;
//8-bit uart;RI0 will only be activated if stop bit is logic level 1.

TR1 = 1;

ET1 = 0;

ES0 = 1;              // Enable UART0 interrupt
}

void hal_uart_tx(byte * pTxBuff,uint length)
{

uart_tx_ptr = pTxBuff;

uart_tx_len = length;

uart_tx_cnt = 0;

uart_tx_completed = 0;

SBUF0 = *uart_tx_ptr;


while(uart_tx_completed == 0);
}

void hal_uart_rx(byte * pRxBuff,uint length)
{

uart_rx_ptr = pRxBuff;

uart_rx_len = length;

uart_rx_cnt = 0;

uart_rx_completed = 0;

while(uart_rx_completed == 0);
}

void hal_uart_tx_overlapped(byte * pTxBuff,uint length)
{

uart_tx_ptr = pTxBuff;

uart_tx_len = length;

uart_tx_cnt = 0;

uart_tx_completed = 0;

SBUF0 = *uart_tx_ptr;

}

void hal_uart_rx_overlapped(byte * pRxBuff,uint length)
{

uart_rx_ptr = pRxBuff;

uart_rx_len = length;

uart_rx_cnt = 0;

uart_rx_completed = 0;
}
void hal_uart_tx_byte(byte txData)
{

hal_uart_tx(&txData,1);
}

byte hal_uart_rx_byte()
{

byte temp;

hal_uart_rx(&temp,1);

return temp;

}

byte hal_uart_rx_count()
{

return uart_rx_cnt;

}
bool hal_uart_tx_complete()
{

return uart_tx_completed;
}

bool hal_uart_rx_complete()
{

return uart_rx_completed;
}

void hal_uart_registe_RecieveEvent(CALLBACKFUNC receiveProc)
{

pHandleReceive = receiveProc;

}

评分

参与人数 1威望 +1 收起 理由
草履虫 + 1 这个思想比LZ的思想要好.中断里尽可能只做 ...

查看全部评分

lgnativs 发表于 2011-11-12 09:44 | 显示全部楼层
我的通用串口程序.
主要功能:
1.能完成同步/异步的多字节发送接收;
2.接收消息回调函数;
第一次贴代码,格式有点乱请见谅.
hotpower 发表于 2011-11-12 12:20 | 显示全部楼层
不错,回调函数上档次。
ningling_21 发表于 2011-11-13 22:36 | 显示全部楼层

这回开眼界了...
sytu_chyq 发表于 2011-11-16 15:07 | 显示全部楼层
我中断程序没那么复杂
只管把数据放入缓存
然后一次性读出
再作判断

评论

你是做arm的?BUFFER有那么大么?反正我都是接受一个处理一个,一般的数据处理还是不会出问题的。我一般给串口2个byte  发表于 2012-12-17 13:07

评分

参与人数 1威望 +1 收起 理由
shizaigaole + 1

查看全部评分

lgnativs 发表于 2011-11-16 15:37 | 显示全部楼层
这个串口程序主要考虑到通用性,是想把它作为一个硬件抽象层来用的(hardware abstract layer).这样就不必每次重写串口程序了.
mugenwon 发表于 2011-11-16 16:07 | 显示全部楼层
本帖最后由 mugenwon 于 2011-11-16 16:12 编辑

哈,我也来一段AVR的吧。没有加入超时处理。因为信号有自动重启功能,在定时器里面也有状态超时切换功能。只帖发送和接收部分。因为某些保密原因状态机,还有程序有所删减。。。数据是不需要校验的,本来就不是数据包。不过在处理数据的地方可以自己加校验。

//接收发送DMX512信号,波特率250K
//**************************************************************
//UART接收中断
//**************************************************************
#pragma interrupt_handler uart0_rx_isr:14        
void uart0_rx_isr(void)
{        uchar sreg=SREG;        
        uchar kudr;
    static uint cc_indata_num;
    static d512_innum;
        
//================================
//接受512数据模式
//================================
if(UCSRA&0x10)        //帧错误,认为是大空挡
{        kudr=UDR;
        if((m_d512_r==M512_CANSTART)&&(kudr==0))
                m_d512_r=M512_STARTB;
}
else
{        kudr=UDR;
    if(m_d512_r==M512_STARTB)                //必须有大空挡才开始
    {        m_d512_r=M512_STARTR;
            
            if(kudr==0)                                        //首字节必须为0,否则通讯状态回到空闲
        {        d512_innum=0;
                      cc_indata_num=0;
        }
        else                                
        {        m_d512_r=M512_CANSTART;
        }
        
    }
    else if(m_d512_r==M512_STARTR)
    {        {        ++d512_innum;
                   if(d512_innum>=set_addr)                                //属于自己的数据
                   {        td_indata_now[cc_indata_num]=kudr;         //放入接收缓冲区   
                           ++cc_indata_num;
                      if(cc_indata_num>=TDINMAX)
                       {        m_d512_r=M512_ENDR;                        //这种状态是处理数据
                           UART_IN_DISABLE;                        //关接受   
                       }
                   }
        }            
    }

}
        SREG=sreg;
}


//**************************************************************
//UART发送中断
//**************************************************************
#pragma interrupt_handler uart0_tx_isr:16
void uart0_tx_isr(void)
{        uchar sreg=SREG;
        static uchar cc_outdata_num;        //发送数据计数器
    uchar i;
    //static uchar td_outdata_setnum;
        if(m_d512_r==M512_SFT)                        //发完包头,发第一个数
        {        m_d512_r=M512_SFD;
        cc_outdata_num=0;
        UDR=td_outdata_now[0];
    }
    else if(m_d512_r==M512_SFD)                //继续发数据
    {        ++cc_outdata_num;
            if(cc_outdata_num<TDOUTMAX)
        {        UDR=td_outdata_now[cc_outdata_num];
        }
        else                                                //发完,切换通讯状态
        {        cc_outdata_num=0;
                m_d512_r=M512_SFE;
        }
        
    }

    SREG=sreg;
}

评论

咋们是一个路子的,用define的少,主要加注释  发表于 2012-12-17 13:08
mugenwon 发表于 2011-11-16 16:09 | 显示全部楼层
本帖最后由 mugenwon 于 2011-11-16 16:19 编辑

一粘贴TAB格式就不好看了。:o
再来个收数据包的:lol ,够简单吧
个人一般不喜欢用指针,除非速度大小有要求的时候我才用。

//**************************************************************
//UART接收中断
//**************************************************************
#pragma interrupt_handler uart0_rx_isr:14
void uart0_rx_isr(void)
{ uchar k;
static uchar c_pccon;
   
    k=UDR;   
    if(mode_conpc==M_PCIN_INS)  //收到指令包头
    { s_data[0]=k;
     mode_conpc=M_PCIN_LEN;
        
    }
    else if(mode_conpc==M_PCIN_LEN) //收到长度
    { s_data[1]=k;
     c_pccon=0;
     mode_conpc=M_PCIN_DATA;
        
    }
    else if(mode_conpc==M_PCIN_DATA)//收到数据
    { s_data[2+c_pccon]=k;
     c_pccon++;
     if(c_pccon>=s_data[1])
         mode_conpc=M_PCIN_SUM;      
    }
    else if(mode_conpc==M_PCIN_SUM) //收到校验和
    { s_data[2+c_pccon]=k;
     mode_conpc=M_PCIN_DATADO;
     
    }
}
hf5542 发表于 2011-11-16 16:29 | 显示全部楼层
围观!
mugenwon 发表于 2011-11-16 16:29 | 显示全部楼层
本帖最后由 mugenwon 于 2011-11-16 16:33 编辑

如果要做的好那可不是那么简单。举个例子,假如数据传输了一半,线断了你怎么办?数据总是出错,数据线被长时间拉低,同一条线又要发又要收,能同时做主机和从机,能改变波特率和通讯格式,甚至还要兼顾非标准的UART(例如要做IO口,或者DMX512数据就是)等等。。。

评论

考虑多了就麻烦了,我以前也搜过类似的问题,似乎记得有人说串口慢,没必要搞那么复杂!  发表于 2012-12-17 13:09
shenhao2007 发表于 2011-11-16 20:06 | 显示全部楼层
高手甚多
lczsx2000 发表于 2011-11-17 13:00 | 显示全部楼层
这么多赞扬的,我来提几个问题,探讨一下吧
1、全局变量太多了
2、都是处理同一个类型的driver程序,是否把全局变量整合成结构体来描述串口这个具体的设备呢
3、void GetFrmData()函数取数据较繁琐,而且没有返回值,不规范
4、int main()函数这样的形式更专业一点吧
5、串口中断程序还是只完成收数据比较好,没必要把状态机放在这里面吧
6、最后,程序里面if和else这样的条件分支太多,程序的逻辑清晰度大大降低

评分

参与人数 2威望 +3 收起 理由
一路向南 + 2
shizaigaole + 1

查看全部评分

shizaigaole 发表于 2011-11-17 14:47 | 显示全部楼层
楼主的程序不咋地。

37楼说的不错
autopccopy 发表于 2011-11-17 18:04 | 显示全部楼层
串口程序,MARK! DING! UP!:lol
hotpower 发表于 2011-11-17 21:12 | 显示全部楼层
总结的不错,6条呀。
nayaix 发表于 2011-11-19 18:01 | 显示全部楼层
......学习了
Periodic 发表于 2011-11-20 09:29 | 显示全部楼层
总体感觉 有点乱
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 在线客服 返回列表 返回顶部