搜索
bottom↓
回复: 57

单片机通用软件模拟串口 三倍采样 同步收发

  [复制链接]

出0入92汤圆

发表于 2018-11-7 12:54:50 | 显示全部楼层 |阅读模式
本人前段时间参考小小调度器写的单片机通用软件模拟串口
使用方法:

1、定义接收和发送的IO口
        //C51
        sbit IO_RX P2^1;
        sbit IO_TX P2^2;
       
        //PIC
        #define        IO_RX RC3        //定义接收的IO口
        #define        IO_TX RC4        //定义发送的IO口
       
2、在main主程序while(1)循环之前加上串口初始化代码
        UART_INIT();
3、设置一个定时器的中断时间为34.6uS,在定时器中断里加上下边的代码
        UART_TX();
        UART_RX();
4、在main主程序while(1)循环中判断,UART_RX_STA标志是否是RX_DATAOK,如果是则收到新数据,可以处理收到的数据或将数据转存。
        if(UART_RX_STA==RX_DATAOK)
        {
                unsigned char dat;
                dat=rx_buff;        //rx_buff里的数据为串口收到的数据
                UART_RREST();        //准备接收下一字节数据
        }
5、在发送数据前判断UART_TX_STA标志是否是TX_FREE空闲状态,是空闲状态
        if(UART_TX_STA==TX_FREE)
        {
                unsigned char dat;
                dat=0xF2;
                UART_TDATA(dat);        //将dat从串口发送出去
        }



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

阿莫论坛20周年了!感谢大家的支持与爱护!!

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。

出0入0汤圆

发表于 2018-11-7 13:25:59 | 显示全部楼层
51和PIC通用。不错。

出90入0汤圆

发表于 2018-11-7 13:31:36 | 显示全部楼层
软件模拟串口,以前用过。

出0入0汤圆

发表于 2018-11-7 13:41:52 | 显示全部楼层
我模拟 UART接收,都是用下沿中断来触发的,程序比LZ的复杂了一点,好在没有数据过来的时候,不会产生频繁的定时中断。

LZ有没有做过长时间接收测试,效果如何

出0入92汤圆

 楼主| 发表于 2018-11-7 13:46:30 | 显示全部楼层
retention 发表于 2018-11-7 13:41
我模拟 UART接收,都是用下沿中断来触发的,程序比LZ的复杂了一点,好在没有数据过来的时候,不会产生频繁 ...

已经用在产品上了的,一直稳定正常

出0入0汤圆

发表于 2018-11-7 14:06:46 | 显示全部楼层
不错,学习一下!

出0入4汤圆

发表于 2018-11-7 14:08:29 | 显示全部楼层
retention 发表于 2018-11-7 13:41
我模拟 UART接收,都是用下沿中断来触发的,程序比LZ的复杂了一点,好在没有数据过来的时候,不会产生频繁 ...

有一点点干扰都会导致接收错误。

我用的定时,以2倍的速度采样,通信很稳定。

出0入0汤圆

发表于 2018-11-7 14:24:00 | 显示全部楼层
laujc 发表于 2018-11-7 14:08
有一点点干扰都会导致接收错误。

我用的定时,以2倍的速度采样,通信很稳定。 ...

你的意思是说用下沿中断触发来接收,容易被干扰吗?

出0入4汤圆

发表于 2018-11-7 14:30:41 | 显示全部楼层
retention 发表于 2018-11-7 14:24
你的意思是说用下沿中断触发来接收,容易被干扰吗?

是的,
不过感觉你不是这么简单处理的吧?

出0入0汤圆

发表于 2018-11-7 14:36:25 | 显示全部楼层
有排版强迫症的患者给他重新排了版。
//串口接收
#define UART_RX()
{
        switch(f_rx.STA)
        {
                case 0:
                {
                        if (IO_RX == 0)
                        {
                                f_rx.STA=1;
                                f_rx.NUM=8;
                                rx_buff=0;
                                f_rx.CNT=0;
                        }
                }break;
                case 1:
                {
                        f_rx.CNT++;
                        if (f_rx.CNT == 3)
                        {
                                if(IO_RX)
                                {
                                        rx_buff|=0x80;
                                }else
                                {
                                        rx_buff&=0x7F;
                                }
                                f_rx.CNT=0;
                                f_rx.NUM--;
                                if (f_rx.NUM > 0)
                                {
                                        rx_buff>>=1;
                                }else
                                {
                                        f_rx.STA=2;
                                }
                        }
                }break;
                case 2:
                {
                        f_rx.CNT++;
                        if (f_rx.CNT == 3)
                        {
                                f_rx.STA = 3;
                        }
                }break;
                default:
                break;
        }
}
#define UART_TX()
{
        switch(f_tx.STA)
        {
                case 0:
                        break;
                case 1:
                {
                        f_tx.CNT++;
                        if (f_tx.CNT == 1)
                        {
                                IO_TX=0;
                        }else if (f_tx.CNT == 3)
                        {
                                f_tx.STA=2;
                                f_tx.CNT=0;
                                f_tx.NUM=8;
                        }
                }break;
                case 2:
                {
                        f_tx.CNT++;
                        if (f_tx.CNT == 1)
                        {
                                IO_TX=tx_buff&0X01;
                                tx_buff=(tx_buff>>1);
                                f_tx.NUM--;
                        }else if (f_tx.CNT == 3)
                        {
                                f_tx.CNT=0;
                                if(f_tx.NUM==0)
                                {
                                        f_tx.STA=3;
                                }
                        }
                }break;
                case 3:
                {
                        f_tx.CNT++;
                        if (f_tx.CNT ==1 )
                        {
                                IO_TX=1;
                        }else if (f_tx.CNT == 3)
                        {
                                f_tx.STA=0;
                        }
                }break;
                default:
                break;
        }
}

出0入0汤圆

发表于 2018-11-7 14:41:03 | 显示全部楼层
我的流程是:MCU使能RX脚的下沿中断,接收到中断后启动  1/9600(9600为波特率)的定时中断,

然后在定时器中断里面接收 8个数据位和一个停止位,最后判断停止位是否为高电平,如果为高电平则认为是合法的数据。。。



经你这么提醒,我采样每个bit的时候,只采样一次的,这里可能会产生搞干扰能力不足的问题,但是碍于定时器中断得太频繁会干扰主程序运行,

所以就没以数倍于波特率的速度来采样

出0入0汤圆

发表于 2018-11-15 17:05:28 | 显示全部楼层
留个记号,有空学习一下

出0入0汤圆

发表于 2019-1-15 16:58:30 | 显示全部楼层
好像有问题,粤原点 试了下,定时是对的
实际上位机COM设置9600 8 1
下面发送0X14,上位机收到0X2C

出0入92汤圆

 楼主| 发表于 2019-1-15 20:00:06 | 显示全部楼层
rootxie 发表于 2019-1-15 16:58
好像有问题,粤原点 试了下,定时是对的
实际上位机COM设置9600 8 1
下面发送0X14,上位机收到0X2C ...

我一直在粤原点上用,很正常的,你设置的定时器中断时间是多少?

出0入0汤圆

发表于 2019-1-15 20:35:03 | 显示全部楼层
我的经验,4倍采样误码率比较低。

出0入0汤圆

发表于 2019-1-15 20:59:00 | 显示全部楼层
说实在话,我从来没用过这种,不过下次有机会可以试一试。。。

出280入168汤圆

发表于 2019-1-15 21:07:13 来自手机 | 显示全部楼层
我也是四倍采样率,可以消除边沿误差与偶发干扰,再低就信不过了。

出0入0汤圆

发表于 2019-1-15 23:19:12 | 显示全部楼层
学习了,有机会验证一下。

出0入0汤圆

发表于 2019-1-16 00:40:38 来自手机 | 显示全部楼层
xyb852 发表于 2019-1-15 20:00
我一直在粤原点上用,很正常的,你设置的定时器中断时间是多少?

83系列,上面的问题是用T0定时,中断34.5us,16M 4T。刚才换成T2,还是将0x14收成34,用的是虚拟串口

出0入92汤圆

 楼主| 发表于 2019-1-16 06:50:35 | 显示全部楼层
rootxie 发表于 2019-1-16 00:40
83系列,上面的问题是用T0定时,中断34.5us,16M 4T。刚才换成T2,还是将0x14收成34,用的是虚拟串口 ...

只要T0的中断时间是对的,T0中断里UART_RX();UART_TX();放的位置对的就不会误码。
中断代码
  1. void interrupt ISR(void) //中断处理程序
  2. {
  3.         if (T0IE && T0IF) //TMRE0中断        约34.6us
  4.         {
  5.                 TMR0 = c_TMR0; //T0置初值 中断时间约34.6us
  6.                 UART_TX(); //串口发送服务
  7.                 UART_RX(); //串口接收服务
  8.                 T0IF = 0; //清T0中断标志
  9.         }
  10. }
复制代码

定时器0初始化
  1. //16M 2T
  2. #define c_TMR0 128                        //定时器0初值 128=34.6us

  3. void Timer0_Init(void)
  4. {
  5.         //option
  6.         T0CS = 0; //0=定时器 1=计数器
  7.         PSA = 0;  //0=预分频给定时器 1=预分频给看门狗
  8.         PS2 = 0;  //预分频
  9.         PS1 = 0;
  10.         PS0 = 0;
  11.         TMR0 = c_TMR0; //赋初值
  12.         T0IF = 0;
  13.         T0IE = 1;
  14.         GIE = 1;
  15. }
复制代码

出0入92汤圆

 楼主| 发表于 2019-1-16 06:54:53 | 显示全部楼层
zhiwei 发表于 2019-1-15 20:35
我的经验,4倍采样误码率比较低。

主要是为了平衡CPU资源占用和误码率,所以选择三倍采样率了

出0入0汤圆

发表于 2019-1-16 08:09:51 来自手机 | 显示全部楼层
跟指令执行周期有关,T2定时器,换成2T指令执行周期就没问题了,我估计1T的应该效果更好

出0入0汤圆

发表于 2019-1-16 09:01:42 | 显示全部楼层
本帖最后由 rootxie 于 2019-1-16 09:06 编辑
xyb852 发表于 2019-1-16 06:50
只要T0的中断时间是对的,T0中断里UART_RX();UART_TX();放的位置对的就不会误码。
中断代码
定时器0初始 ...


这个初始值好像很奇怪,128
TIMER0 的定时中断为 1/16M   * 2T * 2(分频) * (256-128) = 32us,实际并不是34.6us
难道是为了平衡其他指令执行消耗的时间留下的buffer?

实际上用T2更好一些,无需赋初始值,但是用4T指令还是不行

下午拿热风枪对着吹一下 看看会不会出现误码

出0入0汤圆

发表于 2019-1-16 09:38:55 | 显示全部楼层
软件模拟串口做好了,很稳定。

出0入0汤圆

发表于 2019-1-16 09:43:49 | 显示全部楼层
有个疑问,好像ADC过采不是每次都进去累加的么!那么
                        f_rx.CNT++;
                        if (f_rx.CNT == 3)
                        {
                                f_rx.STA = 3;
                        }
像这段代码,只有累加三次后才进去判断,能算是过采么?请教!

出0入0汤圆

发表于 2019-1-16 11:03:15 来自手机 | 显示全部楼层
粤原点的ide是不是会破坏原来的mplab

出0入92汤圆

 楼主| 发表于 2019-1-16 20:57:20 | 显示全部楼层
sup888 发表于 2019-1-16 09:43
有个疑问,好像ADC过采不是每次都进去累加的么!那么
                        f_rx.CNT++;
               ...

这里是等待停止位时间结束

出0入92汤圆

 楼主| 发表于 2019-1-16 20:59:58 | 显示全部楼层
rootxie 发表于 2019-1-16 09:01
这个初始值好像很奇怪,128
TIMER0 的定时中断为 1/16M   * 2T * 2(分频) * (256-128) = 32us,实际并 ...

还有中断后现场保护代码执行占用的时间

出0入92汤圆

 楼主| 发表于 2019-3-22 08:23:56 | 显示全部楼层
2019-03-22 更新1.11版:
     取消结构体的定义,解决部分冷门单片机编译器的兼容问题。
     兼容的代价是,RAM的占用从1.01版的4字节增加到8字节.

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2019-3-22 08:37:59 | 显示全部楼层
STM32 本身有好几个串口,本身的串口  和 模拟的。10个应该没问题

出0入92汤圆

 楼主| 发表于 2019-3-22 11:43:17 | 显示全部楼层
woshigeshuai 发表于 2019-3-22 08:37
STM32 本身有好几个串口,本身的串口  和 模拟的。10个应该没问题

以后有时间争取再搞一个支持扩展多个模拟串口的版本

出0入0汤圆

发表于 2019-3-22 15:31:35 | 显示全部楼层
3倍率应该是比较合适的,误差范围也是可以的,我自己在慢速通信时喜欢用自己做的模拟UART,还能用单IO口做半双工通信,用在产品上一直很稳定

出0入0汤圆

发表于 2019-4-20 21:01:36 | 显示全部楼层
mark,备用......

出0入0汤圆

发表于 2019-12-26 20:32:54 | 显示全部楼层
大佬们好,有不有在粤原点上使用的完整例程啊,我鼓捣不好嗯。

出0入0汤圆

发表于 2019-12-26 23:02:27 | 显示全部楼层
模拟串口,不错

出0入92汤圆

 楼主| 发表于 2019-12-27 21:25:50 | 显示全部楼层
throg 发表于 2019-12-26 20:32
大佬们好,有不有在粤原点上使用的完整例程啊,我鼓捣不好嗯。

明天争取搞一个完整例程发上来

出0入0汤圆

发表于 2020-1-1 18:35:28 | 显示全部楼层
xyb852 发表于 2019-12-27 21:25
明天争取搞一个完整例程发上来

大佬,我照着整了一个,一直在无限的发发发发,帮看下那里不对哟。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2020-1-1 22:28:37 | 显示全部楼层
throg 发表于 2020-1-1 18:35
大佬,我照着整了一个,一直在无限的发发发发,帮看下那里不对哟。

又整了一个,这个可以发送一次,但是不会接收

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入92汤圆

 楼主| 发表于 2020-1-2 10:32:35 | 显示全部楼层
throg 发表于 2020-1-1 22:28
又整了一个,这个可以发送一次,但是不会接收

最近特别忙
我发一个之前测试的MS84F的调度器+软件串口上来给你参考,软件串口请替换成本贴的稳定版.


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2020-3-10 23:39:16 | 显示全部楼层
感谢,我拿来用了

出0入92汤圆

 楼主| 发表于 2020-5-27 14:34:25 | 显示全部楼层
2020-05-27更新1.20版:
      优化结构体定义,修改了接收发送缓存的定义
      优化串口接收部分,接收更稳定正确

异步收发                接收和发送同时进行互不影响
三倍采样率        如9600波特率,定时器中断时间为34.6uS
使用方法:

1、定义接收和发送的IO口
        //C51
        sbit IO_RX P2^1;
        sbit IO_TX P2^2;
       
        //PIC
        #define        IO_RX RC3        //定义接收的IO口
        #define        IO_TX RC4        //定义发送的IO口
       
2、在main主程序while(1)循环之前加上串口初始化代码
        UART_INIT();
3、设置一个定时器的中断时间为34.6uS,在定时器中断里加上下边的代码
        UART_TX();
        UART_RX();
4、在main主程序while(1)循环中判断,UART_RX_STA标志是否是RX_DATAOK,如果是则收到新数据,可以处理收到的数据或将数据转存。
        if(UART_RX_STA==RX_DATAOK)
        {
                unsigned char dat;
                dat=UART_RX_BUFF;        //UART_RX_BUFF里的数据为串口收到的数据
                UART_RREST();        //准备接收下一字节数据
        }
5、在发送数据前判断UART_TX_STA标志是否是TX_FREE空闲状态,是空闲状态
        if(UART_TX_STA==TX_FREE)
        {
                unsigned char dat;
                dat=0xF2;
                UART_TDATA(dat);        //将dat从串口发送出去
        }


本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出5入10汤圆

发表于 2020-5-28 21:22:56 | 显示全部楼层
这个挺好,下载测试下

出0入135汤圆

发表于 2020-5-29 09:33:32 来自手机 | 显示全部楼层
没看出来哪里三倍采样了,纯等待时间,并没有多次采样判断干扰,可能我水平低,有谁看出来的提点一下

出0入0汤圆

发表于 2020-5-29 21:26:24 来自手机 | 显示全部楼层
学习一下,准备测试

出0入0汤圆

发表于 2020-6-4 11:35:20 | 显示全部楼层
xyb852 发表于 2020-5-27 14:34
2020-05-27更新1.20版:
      优化结构体定义,修改了接收发送缓存的定义
      优化串口接收部分,接收更 ...

请教个问题,发送字符串怎么比较好,有没有不一直占用等待单字节的代码,以供参考。谢谢

出0入0汤圆

发表于 2020-6-4 11:37:23 | 显示全部楼层

留个记号,有空学习一下

出0入92汤圆

 楼主| 发表于 2020-6-4 18:34:25 | 显示全部楼层
shower.xu 发表于 2020-6-4 11:35
请教个问题,发送字符串怎么比较好,有没有不一直占用等待单字节的代码,以供参考。谢谢 ...

可以用论坛里的小小调度器,可以找找楼上有例子可以参考

出0入0汤圆

发表于 2020-6-18 09:03:12 | 显示全部楼层
不错,学习一下!

出0入0汤圆

发表于 2020-6-18 12:35:57 | 显示全部楼层
早期用PIC和台湾MCU很多都是用模拟串口,非常稳定

出0入92汤圆

 楼主| 发表于 2020-6-20 21:23:36 | 显示全部楼层
Bicycle 发表于 2019-1-16 11:03
粤原点的ide是不是会破坏原来的mplab

新版的辉芒和粤原点的IDE,C编译器会互相冲突,也和MPLAB的PICC编译器冲突。基本是只能用一个。

出0入92汤圆

 楼主| 发表于 2020-6-20 21:40:17 | 显示全部楼层
yelong98 发表于 2020-5-29 09:33
没看出来哪里三倍采样了,纯等待时间,并没有多次采样判断干扰,可能我水平低,有谁看出来的提点一下 ...

可能是我理解的不一样,这里的意思是把基准时间分成三等份,采样点的位置在三份的交汇点上。

出0入4汤圆

发表于 2020-8-17 15:50:29 | 显示全部楼层
正在研究模拟串口,多谢分享!

出0入4汤圆

发表于 2020-8-17 21:43:44 | 显示全部楼层
在STM32上成功移植。

出0入0汤圆

发表于 2021-5-14 21:23:15 | 显示全部楼层
好好研究一下

出0入4汤圆

发表于 2021-5-14 23:25:53 来自手机 | 显示全部楼层
这个中断cpu太频繁了吧

出105入79汤圆

发表于 2021-5-16 02:11:53 | 显示全部楼层
本帖最后由 qwe2231695 于 2021-5-16 02:16 编辑

要进行115200通信 , 一秒钟中断345600次, 每次间隔0.0029ms , 约3us.  中断占用必须短,用汇编.

出0入13汤圆

发表于 2021-6-29 14:16:26 | 显示全部楼层
楼主使用的这个方法很好,最近可能用得上
感谢分享

出0入0汤圆

发表于 2021-6-29 16:10:58 | 显示全部楼层
有机会验证一下。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-3-29 18:43

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表