找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1784|回复: 13
收起左侧

STC8a8k64d4单片机芯片与RS485通信

[复制链接]
ID:1082545 发表于 2023-7-6 10:53 | 显示全部楼层 |阅读模式
PC机是主机,扩展板是从机,主机发送字符串,从机接收并把字符串发送至PC机。串口助手现象:发送字符串,返回数据是拆分成的单个字符分多次发送。
求大佬分析分析

00_test0_uart2.rar

49.25 KB, 下载次数: 21

代码

回复

使用道具 举报

ID:1006638 发表于 2023-7-6 15:09 | 显示全部楼层
最好把程序和调试画面截图,你整个这,别人给你指导还得费时间下载,大师们很忙的
回复

使用道具 举报

ID:161164 发表于 2023-7-7 16:14 | 显示全部楼层
阻塞式延时令串口助手认为数据是分开的
2023-07-07_160930.png



建议改为非阻塞式
2023-07-07_161119.png

回复

使用道具 举报

ID:624769 发表于 2023-7-7 23:27 来自手机 | 显示全部楼层
建议直接用带485接口的单片机,也不比stc8a8k64d 贵。
回复

使用道具 举报

ID:1082545 发表于 2023-7-10 10:27 | 显示全部楼层
按照三楼修改前后对比
修改前
  1. #include <STC8A8K64D4.H>
  2. #include <intrins.h>
  3. #include <main.h>

  4. #define MAIN_Fosc       11059200L   //定义主时钟(精确计算115200波特率)

  5. #define Baudrate3   115200L
  6. #define UART3_BUF_LENGTH    64

  7. sbit RS485_DIR = P3^6; //RS485 方向选择引脚
  8. sbit         LED = P1^5;//检测代码指示灯引脚

  9. u8  TX3_Cnt;    //发送计数
  10. u8  RX3_Cnt;    //接收计数
  11. bit B_TX3_Busy; //发送忙标志

  12. u8  idata RX3_Buffer[UART3_BUF_LENGTH]; //接收缓冲
  13. u8  idata TX3_Buffer[UART3_BUF_LENGTH]; //发送缓冲
  14. void         play();
  15. void        delay_10us(u16 ten_us);
  16. void PrintString3(u8 *puts);

  17. //延时10us函数
  18. void delay10us(u16 i)
  19. {
  20.         do
  21.         {
  22.                 _nop_();
  23.                 _nop_();
  24.                 _nop_();
  25.                 _nop_();
  26.                 _nop_();
  27.                 _nop_();
  28.                 _nop_();
  29.                 _nop_();
  30.         }while(--i);
  31. }

  32. void Delay1ms()                //@11.0592MHz
  33. {
  34.         unsigned char i, j;

  35.         i = 15;
  36.         j = 90;
  37.         do
  38.         {
  39.                 while (--j);
  40.         } while (--i);
  41. }

  42. //指示灯检测运行函数
  43. void play()
  44. {
  45.        
  46.        
  47.         LED = 0;
  48.         delay10us(500000);       
  49.         LED = 1;
  50.         delay10us(500000);       
  51. }
  52. void Uart3Isr() interrupt 17
  53. {
  54.        
  55.     if((S3CON & 0x01) != 0)//RI 接收
  56.     {       
  57.                 S3CON &= ~0x01;    //Clear Rx flag
  58.         
  59.         OUT1 = !OUT1;
  60.                
  61.                 RX3_Buffer[RX3_Cnt] = S3BUF;
  62.                
  63.         if(++RX3_Cnt >= UART3_BUF_LENGTH)   RX3_Cnt = 0;
  64.                
  65.     }

  66.     if((S3CON & 0x02) != 0) //TI 发送
  67.     {
  68.                 S3CON &= ~0x02;    //Clear Tx flag
  69.                
  70.                 OUT5 = !OUT5;
  71.         
  72.         B_TX3_Busy = 0;

  73.                
  74.     }
  75. }



  76. void Uart3Init()
  77. {
  78.         RS485_DIR = 0; //RS485 设置为接收方向
  79.         P0M0 = 0xfb; P0M1 = 0x00;
  80.     P1M0 = 0x1f; P1M1 = 0x1e;
  81.     P2M0 = 0xff; P2M1 = 0x07;
  82.     P3M0 = 0xb8; P3M1 = 0xb0;
  83.     P4M0 = 0x1f; P4M1 = 0x16;
  84.     P5M0 = 0x2e; P5M1 = 0x2d;
  85.        
  86.         OUT1 = 0;        OUT7 = 0;        OUT13 = 0;
  87.     OUT2 = 0;   OUT8 = 0;        OUT14 = 0;
  88.         OUT3 = 0;        OUT9 = 0;        OUT15 = 1;
  89.         OUT4 = 0;        OUT10 = 0;        OUT16 = 1;
  90.         OUT5 = 0;        OUT11 = 0;
  91.         OUT6 = 0;        OUT12 = 0;
  92.        
  93.        
  94.        
  95.         S3CON = 0x50;       //8位数据, 使用Timer3做波特率发生器, 允许接收
  96.     T3H = (65536UL - (MAIN_Fosc / 4) / Baudrate3) / 256;
  97.     T3L = (65536UL - (MAIN_Fosc / 4) / Baudrate3) % 256;
  98.     T4T3M = 0x0a;
  99.        
  100.         IE2 |= 0x08;          //允许UART3中断

  101.     B_TX3_Busy = 0;
  102.     TX3_Cnt = 0;
  103.     RX3_Cnt = 0;
  104.        
  105.         P_SW2 &= ~0x02;
  106.     P_SW2 |= 0x02;      //UART3 switch bit1 to: 0: P0.0 P0.1,  1: P5.0 P5.1
  107.        
  108. }

  109. //========================================================================
  110. // 函数: void PrintString3(u8 *puts)
  111. // 描述: 串口3发送字符串函数。
  112. // 参数: puts:  字符串指针.
  113. // 返回: none.
  114. // 版本: VER1.0
  115. // 日期: 2014-11-28
  116. // 备注:
  117. //========================================================================
  118. void PrintString3(u8 *puts)
  119. {
  120.         RS485_DIR = 1; //RS485 设置为发送
  121.         delay10us(100); //等待最后的停止位完成,延时时间由波特率决定
  122.     for (; *puts != 0;  puts++)     //遇到停止符0结束
  123.     {
  124.         S3BUF = *puts;
  125.         B_TX3_Busy = 1;
  126.         while(B_TX3_Busy);
  127.     }
  128.         delay10us(100); //等待最后的停止位完成,延时时间由波特率决定
  129.         RS485_DIR = 0;
  130. }

  131. //========================================================================
  132. // 函数: void main(void)
  133. // 描述: 主函数。
  134. // 参数: none.
  135. // 返回: none.
  136. // 版本: VER1.0
  137. // 日期: 2014-11-28
  138. // 备注:
  139. //========================================================================
  140. void main()
  141. {
  142.     Uart3Init();
  143.     //IE2 = 0x08;
  144.     EA = 1;//开总中断
  145.        
  146.     PrintString3("STC");  //UART3发送一个字符串
  147.    
  148.         while (1)
  149.     {
  150.                 play();
  151.                
  152.                 if((TX3_Cnt != RX3_Cnt) && (!B_TX3_Busy))   //收到数据, 发送空闲
  153.         {
  154.                         RS485_DIR = 1; //RS485 设置为发送
  155.                         Delay1ms(); //等待最后的停止位完成,延时时间由波特率决定
  156.                        
  157.                         B_TX3_Busy = 1;
  158.                         S3BUF = RX3_Buffer[TX3_Cnt];
  159.                        
  160.             if(++TX3_Cnt >= UART3_BUF_LENGTH)   TX3_Cnt = 0;
  161.                
  162.                        
  163.                         Delay1ms(); //等待最后的停止位完成,延时时间由波特率决定
  164.                         RS485_DIR = 0;
  165.         }
  166.         
  167.                
  168.     }
  169. }
复制代码


修改后
  1. #include <STC8A8K64D4.H>
  2. #include <intrins.h>
  3. #include <main.h>

  4. #define MAIN_Fosc       11059200L   //定义主时钟(精确计算115200波特率)

  5. #define Baudrate3   115200L
  6. #define UART3_BUF_LENGTH    64

  7. sbit RS485_DIR = P3^6; //RS485 方向选择引脚
  8. sbit         LED = P1^5;//检测代码指示灯引脚

  9. u8  TX3_Cnt;    //发送计数
  10. u8  RX3_Cnt;    //接收计数
  11. bit B_TX3_Busy; //发送忙标志

  12. u8  idata RX3_Buffer[UART3_BUF_LENGTH]; //接收缓冲
  13. u8  idata TX3_Buffer[UART3_BUF_LENGTH]; //发送缓冲
  14. void         play();
  15. void        delay_10us(u16 ten_us);
  16. void PrintString3(u8 *puts);

  17. //延时10us函数
  18. void delay10us(u16 i)
  19. {
  20.         do
  21.         {
  22.                 _nop_();
  23.                 _nop_();
  24.                 _nop_();
  25.                 _nop_();
  26.                 _nop_();
  27.                 _nop_();
  28.                 _nop_();
  29.                 _nop_();
  30.         }while(--i);
  31. }

  32. void Delay1ms()                //@11.0592MHz
  33. {
  34.         unsigned char i, j;

  35.         i = 15;
  36.         j = 90;
  37.         do
  38.         {
  39.                 while (--j);
  40.         } while (--i);
  41. }

  42. //指示灯检测运行函数
  43. void play()
  44. {
  45.         static u32 delayLed = 0;
  46.         if(++delayLed >= 5000)
  47.         {
  48.                 delayLed = 0;
  49.                 LED = !LED;
  50.         }
  51.                
  52. }
  53. void Uart3Isr() interrupt 17
  54. {
  55.        
  56.     if((S3CON & 0x01) != 0)//RI 接收
  57.     {       
  58.                 S3CON &= ~0x01;    //Clear Rx flag
  59.         
  60.         OUT1 = !OUT1;
  61.                
  62.                 RX3_Buffer[RX3_Cnt] = S3BUF;
  63.                
  64.         if(++RX3_Cnt >= UART3_BUF_LENGTH)   RX3_Cnt = 0;
  65.                
  66.     }

  67.     if((S3CON & 0x02) != 0) //TI 发送
  68.     {
  69.                 S3CON &= ~0x02;    //Clear Tx flag
  70.                
  71.                 OUT5 = !OUT5;
  72.         
  73.         B_TX3_Busy = 0;

  74.                
  75.     }
  76. }



  77. void Uart3Init()
  78. {
  79.         RS485_DIR = 0; //RS485 设置为接收方向
  80.         P0M0 = 0xfb; P0M1 = 0x00;
  81.     P1M0 = 0x1f; P1M1 = 0x1e;
  82.     P2M0 = 0xff; P2M1 = 0x07;
  83.     P3M0 = 0xb8; P3M1 = 0xb0;
  84.     P4M0 = 0x1f; P4M1 = 0x16;
  85.     P5M0 = 0x2e; P5M1 = 0x2d;
  86.        
  87.         OUT1 = 0;        OUT7 = 0;        OUT13 = 0;
  88.     OUT2 = 0;   OUT8 = 0;        OUT14 = 0;
  89.         OUT3 = 0;        OUT9 = 0;        OUT15 = 1;
  90.         OUT4 = 0;        OUT10 = 0;        OUT16 = 1;
  91.         OUT5 = 0;        OUT11 = 0;
  92.         OUT6 = 0;        OUT12 = 0;
  93.        
  94.        
  95.        
  96.         S3CON = 0x50;       //8位数据, 使用Timer3做波特率发生器, 允许接收
  97.     T3H = (65536UL - (MAIN_Fosc / 4) / Baudrate3) / 256;
  98.     T3L = (65536UL - (MAIN_Fosc / 4) / Baudrate3) % 256;
  99.     T4T3M = 0x0a;
  100.        
  101.         IE2 |= 0x08;          //允许UART3中断

  102.     B_TX3_Busy = 0;
  103.     TX3_Cnt = 0;
  104.     RX3_Cnt = 0;
  105.        
  106.         P_SW2 &= ~0x02;
  107.     P_SW2 |= 0x02;      //UART3 switch bit1 to: 0: P0.0 P0.1,  1: P5.0 P5.1
  108.        
  109. }

  110. //========================================================================
  111. // 函数: void PrintString3(u8 *puts)
  112. // 描述: 串口3发送字符串函数。
  113. // 参数: puts:  字符串指针.
  114. // 返回: none.
  115. // 版本: VER1.0
  116. // 日期: 2014-11-28
  117. // 备注:
  118. //========================================================================
  119. void PrintString3(u8 *puts)
  120. {
  121.         RS485_DIR = 1; //RS485 设置为发送
  122.         delay10us(100); //等待最后的停止位完成,延时时间由波特率决定
  123.     for (; *puts != 0;  puts++)     //遇到停止符0结束
  124.     {
  125.         S3BUF = *puts;
  126.         B_TX3_Busy = 1;
  127.         while(B_TX3_Busy);
  128.     }
  129.         delay10us(100); //等待最后的停止位完成,延时时间由波特率决定
  130.         RS485_DIR = 0;
  131. }

  132. //========================================================================
  133. // 函数: void main(void)
  134. // 描述: 主函数。
  135. // 参数: none.
  136. // 返回: none.
  137. // 版本: VER1.0
  138. // 日期: 2014-11-28
  139. // 备注:
  140. //========================================================================
  141. void main()
  142. {
  143.     Uart3Init();
  144.     //IE2 = 0x08;
  145.     EA = 1;//开总中断
  146.        
  147.     PrintString3("STC");  //UART3发送一个字符串
  148.    
  149.         while (1)
  150.     {
  151.                 play();
  152.                
  153.                 if((TX3_Cnt != RX3_Cnt) && (!B_TX3_Busy))   //收到数据, 发送空闲
  154.         {
  155.                         RS485_DIR = 1; //RS485 设置为发送
  156.                         Delay1ms(); //等待最后的停止位完成,延时时间由波特率决定
  157.                        
  158.                         B_TX3_Busy = 1;
  159.                         S3BUF = RX3_Buffer[TX3_Cnt];
  160.                        
  161.             if(++TX3_Cnt >= UART3_BUF_LENGTH)   TX3_Cnt = 0;
  162.                
  163.                        
  164.                         Delay1ms(); //等待最后的停止位完成,延时时间由波特率决定
  165.                         RS485_DIR = 0;
  166.         }
  167.         
  168.                
  169.     }
  170. }
复制代码
屏幕截图 2023-07-10 102148.png
屏幕截图 2023-07-10 102610.png
回复

使用道具 举报

ID:1082545 发表于 2023-7-10 10:28 | 显示全部楼层
大IGBT 发表于 2023-7-6 15:09
最好把程序和调试画面截图,你整个这,别人给你指导还得费时间下载,大师们很忙的

谢谢您的建议。
回复

使用道具 举报

ID:1082545 发表于 2023-7-10 10:35 | 显示全部楼层
lkc8210 发表于 2023-7-7 16:14
阻塞式延时令串口助手认为数据是分开的

谢谢您的建议,我修改后发现,第一个字节可以发送并正确回传给串口助手,第二个字节变成“.”,之后字节回传不了
回复

使用道具 举报

ID:1082545 发表于 2023-7-10 14:41 | 显示全部楼层
改动点1:在play()中,delay10us(500000)修改成delay(5000);
  1. LED = 0;
  2.         delay10us(5000);       
  3.         LED = 1;
  4.         delay10us(5000);
复制代码

最新现象:发送aaaaaa,接收aaaaaa
改动点2:在while(1)中去掉play,增加Delay1ms();延时,达到发送aaaaaa,接收aaaaaa

屏幕截图 2023-07-10 144055.png

评分

参与人数 1黑币 +20 收起 理由
admin + 20 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

ID:161164 发表于 2023-7-10 15:01 | 显示全部楼层
Jisuzai 发表于 2023-7-10 10:35
谢谢您的建议,我修改后发现,第一个字节可以发送并正确回传给串口助手,第二个字节变成“.”,之后字节 ...

485通信还是等接收超时后再传会吧
回复

使用道具 举报

ID:1082545 发表于 2023-7-11 11:06 | 显示全部楼层
有个思路问题,PC机发送多个字节字符串后,数据是通过串口中断RX3_Buffer[RX3_Cnt] = S3BUF;从接收SBUF里传给接收缓冲数组RX3_Buffer[RX3_Cnt],RX3_Cnt会不断增加吗
在收到数据后,准备发送时,while(1)循环中if语句是怎么变化的,以及当一个字节数据传给发送寄存器SBUF后,串口检测到SBUF中数据后,直接发给PC机吗
回复

使用道具 举报

ID:1034262 发表于 2023-7-11 13:27 | 显示全部楼层
188610329 发表于 2023-7-7 23:27
建议直接用带485接口的单片机,也不比stc8a8k64d 贵。

没听说过单片机直接带485驱动,什么型号的?485驱动一般可以容忍12V,而单片机通常都不行。
回复

使用道具 举报

ID:1034262 发表于 2023-7-11 13:28 | 显示全部楼层
异步串口转发的,一定要开收发缓冲。
回复

使用道具 举报

ID:1082545 发表于 2023-7-12 09:06 | 显示全部楼层
coody_sz 发表于 2023-7-11 13:27
没听说过单片机直接带485驱动,什么型号的?485驱动一般可以容忍12V,而单片机通常都不行。

485芯片:SP485EEN-L/TR
回复

使用道具 举报

ID:1082545 发表于 2023-7-12 09:06 | 显示全部楼层
原理图
6dfc910fa25a278b24f07ff1b17facb.jpg
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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