找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 4530|回复: 10
收起左侧

STC12单片机的串口1和2为何传输质量差别很远?

[复制链接]
ID:283954 发表于 2019-2-8 01:23 | 显示全部楼层 |阅读模式
这是我这新年写的单片机串口通讯程序,必须两个串口能同时收也同时发,比如1收后再从1输出,也向2输出,2收后再从2输出,也向1输出,用串口助s手以1MS间隔自动向单片机发送,并接收回来的字串,实验结果是:

1. 串口1收后向串口1发送,并向串口2发送,从9600-115200,运行一小时都不会有乱码。

2. 串口2收后向串口1发送,从9600-115200,一点都没问题。
3. 串口2收后向串口2发送,接收几百到几千byte后就会死机,有时两个byte就死机,换了各种频率的晶振,尝试各种速率,都无法解决问题。

由于无法知道死机的位置,于是用T0写了个流水灯观察,发现死机后流水灯还会动,表示程序没有跑飞,几番实验,终于确定是死在对busybit(41H)的检测,把这条检测 “JB 41H, CHECKBUSY2"去掉就不再死机,但每接收到几百个byte就会有遗失一两个字符,怀疑是速率太快,但降到19200也是如此,上网查了一下没什么资料,看说明书也没提到这些,只好来请教各位前辈了,问题如下:

1. 为何串口2的S2TI,S2RI都不能位寻址,设定手续麻烦,是否因此影响到串口2的通讯质量。
2. 有没有其他单片机有比较好的串口(能位寻址)。

我接下来需要做有四个串口的板,串口搞不好就只能作罢了。

uart2-TEST.jpg UARTTEST1.jpg



;THIS IS FOR UART TEST

FIRSTBUFFER EQU 80H
LASTBUFFER EQU 0FFH
BRT EQU 09CH
;------------THIS FOR PCON.7=0 256-X=A
;247(11.0592, 38400) 253(11.0592 115200) 245(11.0592 MIDI 31.4) 238(19200) 220(9600)
;251(18.4320 115200) 241(18.432 38400) 226(18.432, 19200) 196(18.432, 9600)
;250(22.1184 115200) 238(22.1184, 38400)
;229(33.1776. 38400) 247(33.1776, 115200) 202(33.1776,19200) 148(33.1776, 9600)
;------------THIS FOR PCON.7=1
;250(3.6864, 38400) 249(3.6864 32U MIDI)
;226(18.432, 38400) 219(18.4320, 2USx16=32U MIDI)
;238(11.0592, 38400) 250(11.0592, 115200) 220(11.0592, 19200) 184(11.0592, 9600) 234(11.0592, 31250 MIDI 2USx16=32US)
;202(33.1776. 38400) 193?(33.1776, 31250 MIDI) 238(33.1776, 115200) 148(33.1776,19200) 40(33.1776, 9600)

BRTLOAD EQU 251
RELOAD_COUNT EQU 251 ;(18.4320M)

S2CON EQU 9AH     ;S2SM0, S2SM1, S2SM2, S2REN, S2TB8, S2RB8, S2TI, S2RI
IE2 EQU 0AFH      ;X, X, X, X, X, X, ESPI, ES2
IP2 EQU 0B5H      ;X,X,X,X,X,X,PSPS,PS2 PSPI=PARITY OF SPI
S2BUF EQU 9BH
LEDTIME EQU 4

AUXR EQU 8EH
AUXR1 EQU 0A2H        ;7,6=PCA-P4,5=SPI-P4,4=S2-P4,3=GF2,2=ADRJ,1,0=DPS
WAKE_CLKO EQU 08FH    ;WAKEUP AND CLOCK OUTPUT CONTROL REGISTER

ORG 0000H
LJMP MAIN
ORG 0003H
LJMP EXT_INT0 ;EXTERNAL INTERRUPT0
ORG 000BH
LJMP TIMER_0  ;TIMER0 INTERRUPT
ORG 0013H
LJMP EXT_INT1 ;EXTERNAL INTERRUPT1
ORG 001BH
LJMP TIMER_1 ;TIMER1 INTERRUPT
ORG 0023H
LJMP UART1    ;UART1 RECEIVED INTERRUPT
ORG 002BH
LJMP ADC      ;T2
ORG 0033H
LJMP LVD
ORG 003BH
LJMP PCA
ORG 0043H
LJMP UART2   ;UART2 RECEIVED INTERRUPT
ORG 004BH
LJMP SPI
ORG 0100H

MAIN:
MOV 75H, #00000001B         ;FOR BIT ROTATE
MOV 3CH, #LEDTIME

MOV R0, #FIRSTBUFFER        ;INIT THE BTYE TO SENT IN BUFFER POINTER
MOV R1, #FIRSTBUFFER        ;INIT THE POINTER FOR BYTE CAN STORE IN BUFFER
MOV WAKE_CLKO,#00000000B    ;ENABLE BRT(=4),T1(=2) T0(=1) HAVE CLOCK OUTPUT BRT@P1.0 T1@P3.5 T0@P3.4
MOV AUXR,#01000100B         ;T0X12,T1X12,UART_M0X6,BRTRUN, ;S2SMOD,BRTX12,EXTRAM, S1BRS(1=UART1 USE BRT 0=USE T1)
MOV TMOD, #00100001B        ;TIMER1 AS 8 BITS RELOAD, TIMER_0 AS MOD 1

LCALL INITIAL_UART1         ;USE BRT AS SERIAL BAUD GENERATE FOR UART1 AS RECEIVED DATA FROM FRONT RECEIVER
LCALL INITIAL_UART2         ;USE BRT AS SERIAL BAUD GENERATE FOR UART2
SETB EA                    ;ENAABLE ALL INTERRUPT
SETB ET0                    ;SWITCH ON T0 INTERRUPT
SETB TR0                    ;RUN TIMER-0

LED:     
DJNZ 3AH, LED1 ;THIS IS FOR LEDSHOWDELAY
DJNZ 3BH, LED1
DJNZ 3CH, LED1
CPL P1.5       ;INDICATE LED LIGHTUP
MOV 3CH, #LEDTIME
LED1:
MOV A, R0
XRL A, R1
JZ LEDEXIT
MOV A, @R0
LCALL SENTONEBYTE1
MOV A, @R0
LCALL SENTONEBYTE2
LCALL NEXTBUFFER0
LEDEXIT:
JMP LED

NEXTBUFFER0:
CJNE R0, #LASTBUFFER, NEXTBUFFER0A
MOV R0, #FIRSTBUFFER
JMP NEXTBUFFER0EXIT
NEXTBUFFER0A:
INC R0  ;POINT TO NEXT BYTE
NEXTBUFFER0EXIT:
RET

INITIAL_UART1:         
MOV SCON, #01010000B   ;SET AS BAUD VERIABLE, NO ODD/EVEN CHECK
MOV TH1, #RELOAD_COUNT        
MOV TL1, #RELOAD_COUNT
SETB PS                         ;SERIAL PORT PRORITY HIGH
SETB TR1                        ;RUN TIMER_1
SETB ES                         ;ENABLE UART1 INTERRUPT
RET

UART1:      
;/*----------------------------
;UART1 INTERRUPT SERVICE ROUTINE
;----------------------------*/
PUSH ACC
PUSH PSW
JNB RI, UART1CHECKTI
CLR RI
MOV A, SBUF                  ;READ THE CHARACTER FROM THE SERIAL PORT
MOV @R1, A
CJNE R1, #LASTBUFFER, NEXTBUFFER1
MOV R1, #FIRSTBUFFER
JMP UART1EXIT
NEXTBUFFER1:
INC R1                       ;POINT TO NEXT BUFFER
JMP UART1EXIT
UART1CHECKTI:
CLR TI
CLR 40H ;NOT BUSY
UART1EXIT:
POP PSW
POP ACC
RETI

SENTONEBYTE1:                ;SENT OUT A
CHECKBUSY1:
JB 40H, CHECKBUSY1
SETB 40H
MOV SBUF, A
RET

INITIAL_UART2:         
MOV S2CON, #01010000B  ;SET AS BAUD VERIABLE, NO ODD/EVEN CHECK
MOV BRT, #BRTLOAD      ;RELOAD
ORL AUXR, #10H         ;BRT START RUN
MOV IP2, #01H          ;UART INTERUUPT PARITY HIGH
MOV IE2, #01H          ;ENABLE UART2 INTERRUPT
RET

UART2:                ;THIS RECEIVED DATA AND STORE TO BUFFER FOR SENT OUT
;/*----------------------------
;UART2 INTERRUPT SERVICE ROUTINE
;----------------------------*/
PUSH ACC
PUSH PSW
MOV  A, S2CON                ;READ UART2 CONTROL REGISTER
ANL A, #00000001B            ;ANL, IF S2RI=0 THEN 0
JZ UART2CHECKTI
MOV A, S2BUF
MOV @R1, A
MOV A, S2CON                 ;READ UART2 CONTROL REGISTER AGAIN
ANL A, #11111110B            ;CLEAR S2RI BIT
MOV S2CON, A                 ;SAVE BACK S2CON
CJNE R1, #LASTBUFFER, NEXTBUFFER2
MOV R1, #FIRSTBUFFER
JMP UART2EXIT
NEXTBUFFER2:
INC R1                       ;POINT TO NEXT BUFFER
JMP UART2EXIT
UART2CHECKTI:                ;NOT USE
MOV A, S2CON                 ;READ UART2 CONTROL REGISTER AGAIN
ANL A, #11111101B            ;CLEAR S2TI BIT
MOV S2CON, A
CLR 41H
CLR 41H
UART2EXIT:
POP    PSW
POP    ACC
RETI

SENTONEBYTE2:        ;SENT OUT DATA IN A
CHECKBUSY2:
JB 41H, CHECKBUSY2
SETB 41H
MOV S2BUF, A
RET

EXT_INT0:            ;IF P3.2 H2L COME HERE SET TIMER, ONLY FIRST H2L WILL ACT
RETI

TIMER_0:             ;USE FOR GENERATE SYS-CLOCK
PUSH ACC
MOV A, 75H
MOV P0, A
RL A
MOV 75H, A
MOV P2, S2CON
MOV TH0, #0      
MOV TL0, #0
POP ACC
RETI

EXT_INT1:        ;USE FOR INFRA RED
RETI
TIMER_1:
RETI
ADC:
RETI
PCA:
RETI
LVD:
RETI
SPI:
RETI


END
uart2-TEST.jpg
回复

使用道具 举报

ID:432823 发表于 2019-2-8 14:55 | 显示全部楼层
串口通讯口2的中断优级较低,这一点要注意。
回复

使用道具 举报

ID:371423 发表于 2019-2-8 17:17 | 显示全部楼层
我曾经用15系列的同时开定时器0、1,ADC、串口1、3的中断。结果串口3,两个字节之间延时达到毫秒才能无漏掉地接收,估计是中断优先级太低的问题。
回复

使用道具 举报

ID:155507 发表于 2019-2-8 20:51 | 显示全部楼层

我给你来个程序试试
STC8A8K64S4A12 单片机的一个4串口同时中断收发的程序,4个全双工串口工作于不同的波特率,115200,57600,38400,19200,然后你可以接4台电脑的串口助手,同时测试,程序会数据原样返回,你可以每个串口测试1M字节看看,没有问题的。
  1. /*********************************************************/
  2. #define MAIN_Fosc  24000000L        //定义主时钟

  3. #include "STC8xxxx.H"


  4. /*************        功能说明        **************

  5. 4串口全双工中断方式收发通讯程序。

  6. 通过PC向MCU发送数据, MCU收到后通过串口把收到的数据原样返回.

  7. 默认参数:
  8. 所有设置均为 1位起始位, 8位数据位, 1位停止位, 无校验.
  9. 每个串口可以使用不同的波特率.
  10. 串口1(P3.0 P3.1): 115200bps.
  11. 串口2(P1.0 P1.1):  57600bps.
  12. 串口3(P0.0 P0.1):  38400bps.
  13. 串口4(P0.2 P0.3):  19200bps.


  14. ******************************************/

  15. /*************        本地常量声明        **************/
  16. #define        RX1_Length        128                /* 接收缓冲长度 */
  17. #define        RX2_Length        128                /* 接收缓冲长度 */
  18. #define        RX3_Length        128                /* 接收缓冲长度 */
  19. #define        RX4_Length        128                /* 接收缓冲长度 */

  20. #define        UART_BaudRate1        115200UL         /* 波特率 */
  21. #define        UART_BaudRate2         57600UL         /* 波特率 */
  22. #define        UART_BaudRate3         38400UL         /* 波特率 */
  23. #define        UART_BaudRate4         19200UL         /* 波特率 */


  24. /*************        本地变量声明        **************/
  25. u8        xdata        RX1_Buffer[RX1_Length];        //接收缓冲
  26. u8        xdata        RX2_Buffer[RX2_Length];        //接收缓冲
  27. u8        xdata        RX3_Buffer[RX3_Length];        //接收缓冲
  28. u8        xdata        RX4_Buffer[RX4_Length];        //接收缓冲

  29. u8        TX1_read,RX1_write;        //读写索引(指针).
  30. u8        TX2_read,RX2_write;        //读写索引(指针).
  31. u8        TX3_read,RX3_write;        //读写索引(指针).
  32. u8        TX4_read,RX4_write;        //读写索引(指针).

  33. bit        B_TX1_Busy,B_TX2_Busy,B_TX3_Busy,B_TX4_Busy;        // 发送忙标志


  34. /*************        本地函数声明        **************/
  35. void        UART1_config(u8 brt);        // 选择波特率, 2: 使用Timer2做波特率, 其它值: 使用Timer1做波特率.
  36. void        UART2_config(u8 brt);        // 选择波特率, 2: 使用Timer2做波特率, 其它值: 无效.
  37. void        UART3_config(u8 brt);        // 选择波特率, 2: 使用Timer2做波特率, 其它值: 使用Timer3做波特率.
  38. void        UART4_config(u8 brt);        // 选择波特率, 2: 使用Timer2做波特率, 其它值: 使用Timer4做波特率.
  39. void         PrintString1(u8 *puts);
  40. void         PrintString2(u8 *puts);
  41. void         PrintString3(u8 *puts);
  42. void         PrintString4(u8 *puts);




  43. //========================================================================
  44. // 函数: void main(void)
  45. // 描述: 主函数
  46. // 参数: none.
  47. // 返回: none.
  48. // 版本: VER1.0
  49. // 日期: 2016-4-28
  50. // 备注:
  51. //========================================================================
  52. void main(void)
  53. {
  54.         EAXRAM();

  55.         UART1_config(1);        // 选择波特率, 2: 使用Timer2做波特率, 其它值: 使用Timer1做波特率.
  56.         UART2_config(2);        // 选择波特率, 2: 使用Timer2做波特率, 其它值: 无效.
  57.         UART3_config(3);        // 选择波特率, 2: 使用Timer2做波特率, 其它值: 使用Timer3做波特率.
  58.         UART4_config(4);        // 选择波特率, 2: 使用Timer2做波特率, 其它值: 使用Timer4做波特率.
  59.        
  60.         EA = 1;

  61.         PrintString1("STC8 serial USART1 Test Prgramme!\r\n");
  62.         PrintString2("STC8 serial USART2 Test Prgramme!\r\n");
  63.         PrintString3("STC8 serial USART3 Test Prgramme!\r\n");
  64.         PrintString4("STC8 serial USART4 Test Prgramme!\r\n");


  65.         while (1)
  66.         {

  67.                 if((TX1_read != RX1_write) && !B_TX1_Busy)        //收到过数据, 并且发送空闲
  68.                 {
  69.                         B_TX1_Busy = 1;                //标志发送忙
  70.                         SBUF = RX1_Buffer[TX1_read];        //发一个字节
  71.                         if(++TX1_read >= RX1_Length)        TX1_read = 0;        //避免溢出处理
  72.                 }

  73.                 if((TX2_read != RX2_write) && !B_TX2_Busy)        //收到过数据, 并且发送空闲
  74.                 {
  75.                         B_TX2_Busy = 1;                //标志发送忙
  76.                         S2BUF = RX2_Buffer[TX2_read];        //发一个字节
  77.                         if(++TX2_read >= RX2_Length)        TX2_read = 0;        //避免溢出处理
  78.                 }

  79.                 if((TX3_read != RX3_write) && !B_TX3_Busy)        //收到过数据, 并且发送空闲
  80.                 {
  81.                         B_TX3_Busy = 1;                //标志发送忙
  82.                         S3BUF = RX3_Buffer[TX3_read];        //发一个字节
  83.                         if(++TX3_read >= RX3_Length)        TX3_read = 0;        //避免溢出处理
  84.                 }

  85.                 if((TX4_read != RX4_write) && !B_TX4_Busy)        //收到过数据, 并且发送空闲
  86.                 {
  87.                         B_TX4_Busy = 1;                //标志发送忙
  88.                         S4BUF = RX4_Buffer[TX4_read];        //发一个字节
  89.                         if(++TX4_read >= RX4_Length)        TX4_read = 0;        //避免溢出处理
  90.                 }
  91.         }
  92. }


  93. //========================================================================
  94. // 函数: SetTimer2Baudraye(u16 dat)
  95. // 描述: 设置Timer2做波特率发生器。
  96. // 参数: dat: Timer2的重装值.
  97. // 返回: none.
  98. // 版本: VER1.0
  99. // 日期: 2016-4-28
  100. // 备注:
  101. //========================================================================
  102. void        SetTimer2Baudraye(u16 dat)        // 选择波特率, 2: 使用Timer2做波特率, 其它值: 使用Timer1做波特率.
  103. {
  104.         AUXR &= ~(1<<4);        //Timer stop
  105.         AUXR &= ~(1<<3);        //Timer2 set As Timer
  106.         AUXR |=  (1<<2);        //Timer2 set as 1T mode
  107.         T2H = dat / 256;
  108.         T2L = dat % 256;
  109.         IE2  &= ~(1<<2);        //禁止中断
  110.         AUXR |=  (1<<4);        //Timer run enable
  111. }


  112. //========================================================================
  113. // 函数: void        UART1_config(u8 brt)
  114. // 描述: UART1初始化函数。
  115. // 参数: brt: 选择波特率, 2: 使用Timer2做波特率, 其它值: 使用Timer1做波特率.
  116. // 返回: none.
  117. // 版本: VER1.0
  118. // 日期: 2016-4-28
  119. // 备注:
  120. //========================================================================
  121. void        UART1_config(u8 brt)        // 选择波特率, 2: 使用Timer2做波特率, 其它值: 使用Timer1做波特率.
  122. {
  123.         u8        i;
  124.         /*********** 波特率使用定时器2 *****************/
  125.         if(brt == 2)
  126.         {
  127.                 AUXR |= 0x01;                //S1 BRT Use Timer2;
  128.                 SetTimer2Baudraye(65536UL - (MAIN_Fosc / 4) / UART_BaudRate1);
  129.         }

  130.         /*********** 波特率使用定时器1 *****************/
  131.         else
  132.         {
  133.                 TR1 = 0;
  134.                 AUXR &= ~0x01;                //S1 BRT Use Timer1;
  135.                 AUXR |=  (1<<6);        //Timer1 set as 1T mode
  136.                 TMOD &= ~(1<<6);        //Timer1 set As Timer
  137.                 TMOD &= ~0x30;                //Timer1_16bitAutoReload;
  138.                 TH1 = (65536UL - (MAIN_Fosc / 4) / UART_BaudRate1) / 256;
  139.                 TL1 = (65536UL - (MAIN_Fosc / 4) / UART_BaudRate1) % 256;
  140.                 ET1 = 0;        //禁止中断
  141.                 //        INT_CLKO &= ~0x02;        //不输出时钟
  142.                 INT_CLKO |=  0x02;        //  输出时钟
  143.                 TR1  = 1;
  144.         }
  145.         /*************************************************/

  146.         SCON = (SCON & 0x3f) | (1<<6);        // 8位数据, 1位起始位, 1位停止位, 无校验
  147.         //        PS  = 1;        //高优先级中断
  148.         ES  = 1;        //允许中断
  149.         REN = 1;        //允许接收
  150.         P_SW1 = P_SW1 & 0x3f;                                P3n_push_pull(0x02);        //切换到 P3.0 P3.1
  151.         //        P_SW1 = (P_SW1 & 0x3f) | (1<<6);        P3n_push_pull(0x80);        //切换到P3.6 P3.7
  152.         //        P_SW1 = (P_SW1 & 0x3f) | (2<<6);        P1n_push_pull(0x80);        //切换到P1.6 P1.7 (必须使用内部时钟)

  153.         for(i=0; i<RX1_Length; i++)                RX1_Buffer[i] = 0;
  154.         B_TX1_Busy  = 0;
  155.         TX1_read    = 0;
  156.         RX1_write   = 0;
  157. }


  158. //========================================================================
  159. // 函数: void        UART2_config(u8 brt)
  160. // 描述: UART2初始化函数。
  161. // 参数: brt: 选择波特率, 2: 使用Timer2做波特率, 其它值: 无效.
  162. // 返回: none.
  163. // 版本: VER1.0
  164. // 日期: 2016-4-28
  165. // 备注:
  166. //========================================================================
  167. void        UART2_config(u8 brt)        // 选择波特率, 2: 使用Timer2做波特率, 其它值: 无效.
  168. {
  169.         u8        i;
  170.         /*********** 波特率固定使用定时器2 *****************/
  171.         if(brt == 2)        SetTimer2Baudraye(65536UL - (MAIN_Fosc / 4) / UART_BaudRate2);

  172.         S2CON &= ~(1<<7);        // 8位数据, 1位起始位, 1位停止位, 无校验
  173.         IE2   |= 1;                        //允许中断
  174.         S2CON |= (1<<4);        //允许接收
  175.         P_SW2 &= ~1;        P1n_push_pull(0x02);        //切换到 P1.0 P1.1
  176.         //        P_SW2 |= 1;                P4n_push_pull(0x80);        //切换到 P4.6 P4.7

  177.         for(i=0; i<RX2_Length; i++)                RX2_Buffer[i] = 0;
  178.         B_TX2_Busy  = 0;
  179.         TX2_read    = 0;
  180.         RX2_write   = 0;
  181. }

  182. //========================================================================
  183. // 函数: void        UART3_config(u8 brt)
  184. // 描述: UART3初始化函数。
  185. // 参数: brt: 选择波特率, 2: 使用Timer2做波特率, 其它值: 使用Timer3做波特率.
  186. // 返回: none.
  187. // 版本: VER1.0
  188. // 日期: 2016-4-28
  189. // 备注:
  190. //========================================================================
  191. void        UART3_config(u8 brt)        // 选择波特率, 2: 使用Timer2做波特率, 其它值: 使用Timer3做波特率.
  192. {
  193.         u8        i;
  194.         /*********** 波特率固定使用定时器2 *****************/
  195.         if(brt == 2)
  196.         {
  197.                 S3CON &= ~(1<<6);        //BRT select Timer2
  198.                 SetTimer2Baudraye(65536UL - (MAIN_Fosc / 4) / UART_BaudRate3);
  199.         }
  200.         /*********** 波特率使用定时器3 *****************/
  201.         else
  202.         {
  203.                 S3CON |= (1<<6);        //BRT select Timer3
  204.                 T4T3M &= 0xf0;                //停止计数, 清除控制位
  205.                 IE2  &= ~(1<<5);        //禁止中断
  206.                 T4T3M |=  (1<<1);        //1T
  207.                 T4T3M &= ~(1<<2);        //定时
  208.                 T4T3M &= ~1;                //不输出时钟
  209.                 T3H = (65536UL - (MAIN_Fosc / 4) / UART_BaudRate3) / 256;
  210.                 T3L = (65536UL - (MAIN_Fosc / 4) / UART_BaudRate3) % 256;
  211.                 T4T3M |=  (1<<3);        //开始运行
  212.         }
  213.        
  214.         S3CON &= ~(1<<5);        //禁止多机通讯方式
  215.         S3CON &= ~(1<<7);        // 8位数据, 1位起始位, 1位停止位, 无校验
  216.         IE2   |=  (1<<3);        //允许中断
  217.         S3CON |=  (1<<4);        //允许接收
  218.         P_SW2 &= ~2;        P0n_push_pull(0x02);        //切换到 P0.0 P0.1
  219.         //        P_SW2 |= 2;                P5n_push_pull(0x02);        //切换到 P5.0 P5.1

  220.         for(i=0; i<RX3_Length; i++)                RX3_Buffer[i] = 0;
  221.         B_TX3_Busy  = 0;
  222.         TX3_read    = 0;
  223.         RX3_write   = 0;
  224. }

  225. //========================================================================
  226. // 函数: void        UART4_config(u8 brt)
  227. // 描述: UART4初始化函数。
  228. // 参数: brt: 选择波特率, 2: 使用Timer2做波特率, 其它值: 使用Timer4做波特率.
  229. // 返回: none.
  230. // 版本: VER1.0
  231. // 日期: 2016-4-28
  232. // 备注:
  233. //========================================================================
  234. void        UART4_config(u8 brt)        // 选择波特率, 2: 使用Timer2做波特率, 其它值: 使用Timer4做波特率.
  235. {
  236.         u8        i;
  237.         /*********** 波特率固定使用定时器2 *****************/
  238.         if(brt == 2)
  239.         {
  240.                 S4CON &= ~(1<<6);        //BRT select Timer2
  241.                 SetTimer2Baudraye(65536UL - (MAIN_Fosc / 4) / UART_BaudRate4);
  242.         }
  243.         /*********** 波特率使用定时器3 *****************/
  244.         else
  245.         {
  246.                 S4CON |= (1<<6);        //BRT select Timer4
  247.                 T4T3M &= 0x0f;                //停止计数, 清除控制位
  248.                 IE2   &= ~(1<<6);        //禁止中断
  249.                 T4T3M |=  (1<<5);        //1T
  250.                 T4T3M &= ~(1<<6);        //定时
  251.                 T4T3M &= ~(1<<4);        //不输出时钟
  252.                 T4H = (65536UL - (MAIN_Fosc / 4) / UART_BaudRate4) / 256;
  253.                 T4L = (65536UL - (MAIN_Fosc / 4) / UART_BaudRate4) % 256;
  254.                 T4T3M |=  (1<<7);        //开始运行
  255.         }
  256.        
  257.         S4CON &= ~(1<<5);        //禁止多机通讯方式
  258.         S4CON &= ~(1<<7);        // 8位数据, 1位起始位, 1位停止位, 无校验
  259.         IE2   |=  (1<<4);        //允许中断
  260.         S4CON |=  (1<<4);        //允许接收
  261.         P_SW2 &= ~4;        P0n_push_pull(0x08);        //切换到 P0.2 P0.3
  262.         //        P_SW2 |= 4;                P5n_push_pull(0x08);        //切换到 P5.2 P5.3

  263.         for(i=0; i<RX4_Length; i++)                RX4_Buffer[i] = 0;
  264.         B_TX4_Busy  = 0;
  265.         TX4_read    = 0;
  266.         RX4_write   = 0;
  267. }


  268. //========================================================================
  269. // 函数: void PrintString1(u8 *puts)
  270. // 描述: 串口1字符串打印函数
  271. // 参数: puts: 字符串指针.
  272. // 返回: none.
  273. // 版本: VER1.0
  274. // 日期: 2016-4-28
  275. // 备注:
  276. //========================================================================
  277. void PrintString1(u8 *puts)
  278. {
  279.         for (; *puts != 0;        puts++)
  280.         {
  281.                 B_TX1_Busy = 1;                //标志发送忙
  282.                 SBUF = *puts;                //发一个字节
  283.                 while(B_TX1_Busy);        //等待发送完成
  284.         }
  285. }

  286. //========================================================================
  287. // 函数: void PrintString2(u8 *puts)
  288. // 描述: 串口2字符串打印函数
  289. // 参数: puts: 字符串指针.
  290. // 返回: none.
  291. // 版本: VER1.0
  292. // 日期: 2016-4-28
  293. // 备注:
  294. //========================================================================
  295. void PrintString2(u8 *puts)
  296. {
  297.         for (; *puts != 0;        puts++)
  298.         {
  299.                 B_TX2_Busy = 1;                //标志发送忙
  300.                 S2BUF = *puts;                //发一个字节
  301.                 while(B_TX2_Busy);        //等待发送完成
  302.         }
  303. }

  304. //========================================================================
  305. // 函数: void PrintString3(u8 *puts)
  306. // 描述: 串口3字符串打印函数
  307. // 参数: puts: 字符串指针.
  308. // 返回: none.
  309. // 版本: VER1.0
  310. // 日期: 2016-4-28
  311. // 备注:
  312. //========================================================================
  313. void PrintString3(u8 *puts)
  314. {
  315.         for (; *puts != 0;        puts++)
  316.         {
  317.                 B_TX3_Busy = 1;                //标志发送忙
  318.                 S3BUF = *puts;                //发一个字节
  319.                 while(B_TX3_Busy);        //等待发送完成
  320.         }
  321. }

  322. //========================================================================
  323. // 函数: void PrintString4(u8 *puts)
  324. // 描述: 串口1字符串打印函数
  325. // 参数: puts: 字符串指针.
  326. // 返回: none.
  327. // 版本: VER1.0
  328. // 日期: 2016-4-28
  329. // 备注:
  330. //========================================================================
  331. void PrintString4(u8 *puts)
  332. {
  333.         for (; *puts != 0;        puts++)
  334.         {
  335.                 B_TX4_Busy = 1;                //标志发送忙
  336.                 S4BUF = *puts;                //发一个字节
  337.                 while(B_TX4_Busy);        //等待发送完成
  338.         }
  339. }



  340. //========================================================================
  341. // 函数: void UART1_int (void) interrupt UART1_VECTOR
  342. // 描述: 串口1中断函数
  343. // 参数: none.
  344. // 返回: none.
  345. // 版本: VER1.0
  346. // 日期: 2016-4-28
  347. // 备注:
  348. //========================================================================
  349. void UART1_int (void) interrupt UART1_VECTOR
  350. {
  351.         if(RI)
  352.         {
  353.                 RI = 0;
  354.                 RX1_Buffer[RX1_write] = SBUF;
  355.                 if(++RX1_write >= RX1_Length)        RX1_write = 0;
  356.         }

  357.         if(TI)
  358.         {
  359.                 TI = 0;
  360.                 B_TX1_Busy = 0;
  361.         }
  362. }

  363. //========================================================================
  364. // 函数: void UART2_int (void) interrupt UART2_VECTOR
  365. // 描述: 串口2中断函数
  366. // 参数: none.
  367. // 返回: none.
  368. // 版本: VER1.0
  369. // 日期: 2016-4-28
  370. // 备注:
  371. //========================================================================
  372. void UART2_int (void) interrupt UART2_VECTOR
  373. {
  374.         if(RI2)
  375.         {
  376.                 CLR_RI2();
  377.                 RX2_Buffer[RX2_write] = S2BUF;
  378.                 if(++RX2_write >= RX2_Length)        RX2_write = 0;
  379.         }

  380.         if(TI2)
  381.         {
  382.                 CLR_TI2();
  383.                 B_TX2_Busy = 0;
  384.         }

  385. }

  386. //========================================================================
  387. // 函数: void UART3_int (void) interrupt UART3_VECTOR
  388. // 描述: 串口3中断函数
  389. // 参数: none.
  390. // 返回: none.
  391. // 版本: VER1.0
  392. // 日期: 2016-4-28
  393. // 备注:
  394. //========================================================================
  395. void UART3_int (void) interrupt UART3_VECTOR
  396. {
  397.         if(RI3)
  398.         {
  399.                 CLR_RI3();
  400.                 RX3_Buffer[RX3_write] = S3BUF;
  401.                 if(++RX3_write >= RX3_Length)        RX3_write = 0;
  402.         }

  403.         if(TI3)
  404.         {
  405.                 CLR_TI3();
  406.                 B_TX3_Busy = 0;
  407.         }

  408. }

  409. //========================================================================
  410. // 函数: void UART4_int (void) interrupt UART4_VECTOR
  411. // 描述: 串口4中断函数
  412. // 参数: none.
  413. // 返回: none.
  414. // 版本: VER1.0
  415. // 日期: 2016-4-28
  416. // 备注:
  417. //========================================================================
  418. void UART4_int (void) interrupt UART4_VECTOR
  419. {
  420.         if(RI4)
  421.         {
  422.                 CLR_RI4();
  423.                 RX4_Buffer[RX4_write] = S4BUF;
  424.                 if(++RX4_write >= RX4_Length)        RX4_write = 0;
  425.         }

  426.         if(TI4)
  427.         {
  428.                 CLR_TI4();
  429.                 B_TX4_Busy = 0;
  430.         }

  431. }

复制代码



STC8系列4个串口全双工同时中断收发测试例程.zip

17.15 KB, 下载次数: 22

评分

参与人数 2黑币 +37 收起 理由
suuy79 + 2 赞一个!
dalaoshi + 35 很给力!

查看全部评分

回复

使用道具 举报

ID:47286 发表于 2019-2-8 22:55 | 显示全部楼层
再看看程序吧 我也用12c做了个东西 串口2和串口屏通讯 速率也是115200 一直没事 用的就是官网给的范例
回复

使用道具 举报

ID:283954 发表于 2019-2-9 02:26 | 显示全部楼层
手头还没有STC8A的开发板,春节过后会买一个来试,我还没有学C,但通过自己写的程序,竟然也看懂C了,逻辑与我的汇编差不多,S2,S3,S4CON都不能位操作,所以都必须先读进A进行and操作再存回,这期间如果刚好传送完毕而SxTI置位,就会被写回的SxCON覆盖,无法产生中断,因此SxBUSY位无法复位,这是我对这一问题的猜想,我今晚把uart1的RI和TI的重置方式改用与UART2的方式,就是读入,AND,再写回三部曲,结果问题就在UART1重现了,也许STC8有对UART进行一些改进也说不定。等试过就知。
回复

使用道具 举报

ID:283954 发表于 2019-2-15 12:40 | 显示全部楼层
dzbj 发表于 2019-2-8 22:55
再看看程序吧 我也用12c做了个东西 串口2和串口屏通讯 速率也是115200 一直没事 用的就是官网给的范例

我也是一直用官网上的范例来用uart2,也没问题,就是不满足把一个BYTE放进SBUF后还要在那等发送完毕产生TI置位才可以走,那段时间全浪费了,这样怎能做出高效的设计。这里网友提供的四个UART同时收发的例子才是正道,所以我开始造一个用STC8AXXXS4的板子来实验。有了四个UART,如果同时收发效果不尽人意,就可以把收和发各自分配给不同的UART,避免意外死机。
回复

使用道具 举报

ID:283954 发表于 2019-2-15 12:53 | 显示全部楼层
yaoji123 发表于 2019-2-8 14:55
串口通讯口2的中断优级较低,这一点要注意。

这个问题我也很困扰,后来也想通了,说明书上都说中断发生后,不会被同级的中断级别所打断,但没有强调这个后来的中断是会被记住的,等当前的中断结束后,就会被执行,所以这里有网友在劝告我们初哥不要在中断程序里搞太多事,把资料移走后就赶快离开,因为在当前的中断程序里呆太久,在那里等待处理的中断又再产生同样的中断,就会遗失一个中断,结果就是死机啦。
回复

使用道具 举报

ID:283954 发表于 2019-2-21 16:44 | 显示全部楼层
这问题最终也解决了,原来要把S2TI清除是可以直接用ANL指令的,只要一个指令:

ANL S2CON, #11111101B            ;CLEAR S2TI BIT

而不必先载入ACC, ANL之后再送回(三个指令):

MOV A, S2CON                             ;READ UART2 CONTROL REGISTER AGAIN
ANL S2CON, #11111101B            ;CLEAR S2TI BIT
MOV S2CON, A

又长知识了,实践是迈向正确的最好办法哈,现在那怕晶振频率到了33M,115200BPS, 疲劳试验几小时也不出错了。

谢谢各位前辈的指导。
回复

使用道具 举报

ID:283954 发表于 2019-5-5 23:50 | 显示全部楼层

STC8-4com.jpg

终于买到STC8的板,可以进行四个串口的实验了,C语言没用过,只只能写个汇编的,有了上次的经验,这次写的很顺利,确定四个串口运作都很正常,但要同时开四个串口助手进行交叉实验实在觉得累,只能这样了。

;THIS FOR STC8 FOUR UART TESTING
;50H FOR UART1 WRITE POINTER
;51H FOR UART2 WRITE POINTER
;52H FOR UART3 WRITE POINTER
;53H FOR UART4 WRITE POINTER
;54H FOR UART1 READ POINTER
;55H FOR UART2 READ POINTER
;56H FOR UART3 READ POINTER
;57H FOR UART4 READ POINTER
;71H DELAY
;72H DELAY
;73H DELAY

;BIT
;40H FOR UART1 BUSY
;41H FOR UART2 BUSY
;42H FOR UART3 BUSY
;43H FOR UART4 BUSY

FIRSTBUFFER EQU 00H
LASTBUFFER EQU 0FFH
INTCLKO EQU 08FH   
IE2 EQU 0AFH           ;X, ET4, ET3, ES4, ES3, ET2, ESPI, ES2
S2CON EQU 9AH          ;S2SM0, S2SM1, S2SM2, S2REN, S2TB8, S2RB8, S2TI, S2RI
S3CON EQU 0ACH         ;SAME AS S2CON
S4CON EQU 84H
S2BUF EQU 9BH
S3BUF EQU 0ADH
S4BUF EQU 85H

T2H EQU 0D6H           
T2L EQU 0D7H  
P4 EQU 0C0H
P5 EQU 0C8H
P6 EQU 0E8H
P7 EQU 0F8H
AUXR EQU 8EH
AUXR2 EQU 08FH
AUXR1 EQU 0A2H

ORG 0000H
LJMP MAIN
ORG 0003H
LJMP EXT_INT0 ;EXTERNAL INTERRUPT0
ORG 000BH
LJMP TIMER_0  ;TIMER0 INTERRUPT
ORG 0013H
LJMP EXT_INT1 ;EXTERNAL INTERRUPT1
ORG 001BH
LJMP TIMER_1  ;TIMER1 INTERRUPT
ORG 0023H
LJMP UART1   
ORG 002BH
LJMP ADC      
ORG 0033H
LJMP LVD
ORG 003BH
LJMP PCA
ORG 0043H
LJMP UART2   
ORG 004BH
LJMP SPI
ORG 0053H
LJMP INT2
ORG 005BH
LJMP INT3
ORG 0063H
LJMP TIMER_2
ORG 0083H
LJMP INT4
ORG 008BH
LJMP UART3
ORG 0093H
LJMP UART4
ORG 009BH
LJMP TIMER_3
ORG 00A3H
LJMP TIMER_4
ORG 00ABH
LJMP CMP

MAIN:
MOV INTCLKO,#00000100B     ;ENABLE T2(=4),T1(=2) T0(=1) HAVE CLOCK OUTPUT T2@P1.3 T1@P3.5 T0@P3.4
MOV TMOD, #00000000B       ;TIMER_1 AS MOD0 (16BIT AUTO LOAD) ;TIMER_0 AS MOD0 MOD1=16BIT NOT AUTO LOAD
                           ;GATE, C/T,M1,M0(T1) GATE, C/T,M1,MO(T0)
MOV AUXR,#00010101B        ;T0x12,T1x12,UART_M0x6,T2RUN,T2C/T,T2x12,EXTRAM,S1ST2(UART1,0=T1 1=T2) ALL USE T2
MOV T2H, #0FFH             ;18.432 38400 12T=FFF6 1T=FF88 T2 RUN AS 16BIT AUTO LOAD
MOV T2L, #88H
SETB ES                    ;ENABLE UART1 INTERRUPT
MOV IE2, #00011001B        ;ENABLE UART4, UART3, UART2 INTERRUPT
LCALL INIT4UART            ;ALL USE TIMER2 AS BAUD RATE GENERATER
SETB EA                    ;ENABLE ALL INTERRUPT

LOOP:
CPL P1.7
;LCALL DELAY3
LCALL READ1
LCALL READ2
LCALL READ3
LCALL READ4
JMP LOOP


READ4:
MOV A, 53H
CJNE A, 58H, READ4A
JMP READ4EXIT
READ4A:
MOV DPH, #4
MOV DPL, 58H
MOVX A, @DPTR
INC 58H
MOV DPH, #0
LCALL SENTONEBYTE4
READ4EXIT:
RET

READ3:
MOV A, 52H
CJNE A, 57H, READ3A
JMP READ3EXIT
READ3A:
MOV DPH, #3
MOV DPL, 57H
MOVX A, @DPTR
INC 57H
MOV DPH, #0
LCALL SENTONEBYTE3
READ3EXIT:
RET


READ2:
MOV A, 51H
CJNE A, 56H, READ2A
JMP READ2EXIT
READ2A:
MOV DPH, #2
MOV DPL, 56H
MOVX A, @DPTR
INC 56H
MOV DPH, #0
LCALL SENTONEBYTE2
READ2EXIT:
RET

READ1:
MOV A, 50H
CJNE A, 55H, READ1A
JMP READ1EXIT
READ1A:
MOV DPH, #1
MOV DPL, 55H
MOVX A, @DPTR
INC 55H
MOV DPH, #0
LCALL SENTONEBYTE1
READ1EXIT:
RET

SENTONEBYTE1:                ;SENT OUT A
CHECKBUSY1:
JB 40H, CHECKBUSY1
SETB 40H
MOV SBUF, A
RET

SENTONEBYTE2:                ;SENT OUT DATA IN A
CHECKBUSY2:
JB 41H, CHECKBUSY2
SETB 41H
MOV S2BUF, A
RET

SENTONEBYTE3:                ;SENT OUT DATA IN A
CHECKBUSY3:
JB 42H, CHECKBUSY3
SETB 42H
MOV S3BUF, A
RET

SENTONEBYTE4:                ;SENT OUT DATA IN A
CHECKBUSY4:
JB 43H, CHECKBUSY4
SETB 43H
MOV S4BUF, A
RET

UART1:      
;/*----------------------------
;UART1 INTERRUPT SERVICE ROUTINE
;----------------------------*/
PUSH ACC
PUSH PSW
JNB RI, UART1CHECKTI
CLR RI
MOV A, SBUF                  ;READ THE CHARACTER FROM THE SERIAL PORT
MOV DPH, #1
MOV DPL, 50H
MOVX @DPTR, A
INC 50H                       ;POINT TO NEXT BUFFER
MOV DPH, #0
JMP UART1EXIT
UART1CHECKTI:
CLR TI
CLR 40H ;NOT BUSY
UART1EXIT:
POP PSW
POP ACC
RETI

UART2:  
;/*----------------------------
;UART2 INTERRUPT SERVICE ROUTINE
;----------------------------*/
PUSH ACC
PUSH PSW
MOV  A, S2CON                ;READ UART2 CONTROL REGISTER
ANL A, #00000001B            ;ANL, IF S2RI=0 THEN 0
JZ UART2CHECKTI
MOV A, S2BUF
MOV DPH, #2
MOV DPL, 51H
MOVX @DPTR, A
ANL S2CON, #11111110B         ;CLEAR S2RI BIT
INC 51H                       ;POINT TO NEXT BUFFER
MOV DPH, #0
JMP UART2EXIT
UART2CHECKTI:               
ANL S2CON, #11111101B        ;CLEAR S2TI BIT
CLR 41H
UART2EXIT:
POP    PSW
POP    ACC
RETI

UART3:  
;/*----------------------------
;UART3 INTERRUPT SERVICE ROUTINE
;----------------------------*/
PUSH ACC
PUSH PSW
MOV  A, S3CON                ;READ UART3 CONTROL REGISTER
ANL A, #00000001B            ;ANL, IF S3RI=0 THEN 0
JZ UART3CHECKTI
MOV A, S3BUF
MOV DPH, #3
MOV DPL, 52H
MOVX @DPTR, A
ANL S3CON, #11111110B        ;CLEAR S3RI BIT
INC 52H                      ;POINT TO NEXT BUFFER
MOV DPH, #0
JMP UART3EXIT
UART3CHECKTI:               
ANL S3CON, #11111101B        ;CLEAR S3TI BIT
CLR 42H
UART3EXIT:
POP    PSW
POP    ACC
RETI

UART4:  
;/*----------------------------
;UART4 INTERRUPT SERVICE ROUTINE
;----------------------------*/
PUSH ACC
PUSH PSW
MOV  A, S4CON                ;READ UART4 CONTROL REGISTER
ANL A, #00000001B            ;ANL, IF S4RI=0 THEN 0
JZ UART4CHECKTI
MOV A, S4BUF
MOV DPH, #4
MOV DPL, 53H
MOVX @DPTR, A
ANL S4CON, #11111110B        ;CLEAR S4RI BIT
INC 53H                      ;POINT TO NEXT BUFFER
MOV DPH, #0
JMP UART4EXIT
UART4CHECKTI:               
ANL S4CON, #11111101B        ;CLEAR S4TI BIT
CLR 43H
UART4EXIT:
POP    PSW
POP    ACC
RETI

DELAY3:
MOV 72H, #255
SLOWDOWN0:
MOV 71H, #125 ;255
SLOWDOWN:
MOV 73H, #11  ;11=18M
SLOWDOWN2:
DJNZ 73H, SLOWDOWN2
DJNZ 71H, SLOWDOWN
DJNZ 72H, SLOWDOWN0
RET

INIT4UART:  
MOV SCON, #01010000B     ;x,MOD1(NOT SAME AS UART1),x,RECEIVE ENABLE
MOV S2CON, #01010000B    ;MOD0,x,x,RECEIVE ENABLE
MOV S3CON, #00010000B    ;MOD0,0=USE T2,x,RECEIVE ENABLE
MOV S4CON, #00010000B    ;MOD0,0=USE T2,x,RECEIVE ENABLE
RET

EXT_INT0:
RETI
TIMER_0:
RETI
EXT_INT1:
RETI
TIMER_1:
RETI
;UART1:   
;RETI
ADC:      
RETI
LVD:
RETI
PCA:
RETI
;UART2:
;RETI
SPI:
RETI
INT2:
RETI
INT3:
RETI
TIMER_2:
RETI
INT4:
RETI
;UART3:
;RETI
;UART4:
;RETI
TIMER_3:
RETI
TIMER_4:
RETI
CMP:
RETI

END




回复

使用道具 举报

ID:55115 发表于 2019-5-31 10:15 | 显示全部楼层
刚下我需要下载来学习学习~
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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