飞鹰嵌入式 发表于 2012-12-17 19:00

linux模拟串口

背景:1、一款只有2个串口的芯片,
         2、需要3个串口
         3、没使用硬件进行串口扩展
基于以上造成了需要模拟串口的后果:
模拟串口步骤
         a、首先创建字符设备驱动
         b、设置定时器,定时器中断中进行发送和接收处理(中断中只做这个事)、定时器中断是波特率的两倍频率,满足采样定理
         c、创建两个内核线程,一个线程用于处理写缓冲,一个线程来处理接收缓存
         d、实现read、write函数,可以两种方式,一是阻塞方式、一是轮询方式,read函数需要和接收缓存线程共同完成、write函数需要和处理写缓存线程共同完成
下面是模拟串口的主要代码
         static irqreturn_t timer_interrupt(int irq,void *id,struct pt_regs *regs)
{

飞鹰嵌入式 发表于 2012-12-17 19:01

static irqreturn_t timer_interrupt(int irq,void *id,struct pt_regs *regs)
{
        static unsigned short tmp_value;
        static unsigned char rx_value;
        static unsigned char tx_en = TRUE;
        static unsigned char RX_flag = FALSE;
        static unsigned char start_flag = FALSE;
        static unsigned char rx_en = FALSE;
        static unsigned char check_rx = 0;
        static unsigned char tx_count = 0;
        static unsigned char rx_count = 0;

        tmp_value = tx_value & 0x0001;
        if(TRUE == TX_flag)//ready for send
        {
                if(TRUE == tx_en)        //send data       
                {
                        gpio_set_value(TXD_PIN,tmp_value);
                        tx_en = FALSE;
                }
                else       //handle data
                {
                        tx_en = TRUE;
                        tx_value = (tx_value >> 1) | 0xfe00;
                        tx_count++;
                }
                if(16 == tx_count) //send bits count
                {
//        printk("tmp_value = %x\n",tmp_value);
                        tx_count = 0;
                        TX_flag = FALSE;
                }
        }
        if(TRUE == RX_flag)//ready for receive
        {

                if(FALSE == rx_en){
                        rx_en = TRUE;
                }
                else //receive data
                {
                        rx_value >>= 1;
                        rx_en = FALSE;
                        if(gpio_get_value(RXD_PIN))
                                rx_value |= 0x80;
                        rx_count++;
                }

                if(8 == rx_count) //receive bits count
                {
                        RX_flag = FALSE;
                //        printk(KERN_INFO"rx = %x\n",rx_value);
               *m_st_uart0RxBuffer.u8pCurrentPtr = rx_value;                                                   //将接收到的数据放到当前最新接收的数据指针中

                IncRxBuffer0(&m_st_uart0RxBuffer.u8pCurrentPtr,1);
                        }

        }
        else
        {
                        if(gpio_get_value(RXD_PIN)){ //judge start bit
                                RX_flag = FALSE;
                                start_flag = TRUE;
                        }
                        else if(TRUE == start_flag)
                        {
                                RX_flag = TRUE;
                                rx_value = 0;
                                rx_count = 0;
                                start_flag = FALSE;
                        //printk(KERN_INFO"ss\n");
                        }

        }
                return IRQ_HANDLED;
}

icecut 发表于 2012-12-17 19:28

搞定了?稳定性如何?

飞鹰嵌入式 发表于 2012-12-20 10:06

icecut 发表于 2012-12-17 19:28 static/image/common/back.gif
搞定了?稳定性如何?

9600的误码率基本很低

icecut 发表于 2012-12-20 11:16

不错....这种做法值得学习

mr.king 发表于 2012-12-20 12:18

由于系统时钟片问题,可能发送接收异常

飞鹰嵌入式 发表于 2012-12-26 13:00

mr.king 发表于 2012-12-20 12:18 static/image/common/back.gif
由于系统时钟片问题,可能发送接收异常

时钟中断优先级不是最高就容易出现误码

john_lee 发表于 2012-12-26 14:09

民用可以,商用慎重,工业及军用就算了。

1187571764 发表于 2012-12-26 14:11

初学ARM的朋友们是否有很多的疑惑,ARM 模块、开发板,销售中提供技术支持

1187571764 发表于 2012-12-26 14:12

如有需要请联系胡** :60494890
页: [1]
查看完整版本: linux模拟串口