1. #include "holychip_define.h"
    2. #define TXD PORTB1
    3. //#define RXD PORTB4
    4. unsigned int Count=0;
    5. unsigned int Time_1s;
    6. unsigned int i ;
    7. void Delay(unsigned char i)
    8. {
    9. while(i--);
    10. }
    11. /*------------------------------------------------
    12. mS延时函数,含有输入参数 unsigned int t,无返回值
    13. unsigned int 是定义无符号字符变量,其值的范围是
    14. 0~1024 精确延时请使用汇编
    15. -------------------------------------------------*/
    16. void DelayMS(unsigned int t)
    17. {
    18. unsigned char count = 195;
    19. while(t--)
    20. {
    21. while(count--);
    22. }
    23. }
    24. void Init(void)
    25. {
    26. PORTB = 0B00110010; //PB1上电高电平
    27. TRISB = 0X00;
    28. PHCON = 0XFF;
    29. PDCON = 0xff;
    30. ODCON = 0X00;
    31. }
    32. void Time0_Init(void)
    33. {
    34. OPTION = 0x16;
    35. T0 = 178; //定时50ms
    36. T0IE = 1;
    37. T0IF = 0;
    38. GIE = 1;
    39. }
    40. void WriteByte(unsigned char Byte)
    41. {
    42. unsigned char i = 8;
    43. TXD = 0; //发送起始位
    44. Delay(25);
    45. //发送8位数据位
    46. while(i--)
    47. {
    48. TXD = (Byte&0x01); //先传最低位
    49. Byte = Byte>>1;
    50. Delay(25);
    51. }
    52. //发送校验位
    53. TXD = 1;
    54. Delay(25);
    55. }
    56. void UART_SendString(unsigned char *buf)
    57. {
    58. while(*buf!='\0')
    59. {
    60. WriteByte(*buf);
    61. buf++;
    62. }
    63. }
    64. void main(void)
    65. {
    66. unsigned int i ;
    67. Init();
    68. Time0_Init();
    69. while(1)
    70. {
    71. if(Time_1s==1)
    72. {
    73. Time_1s=0;
    74. for(i=0;i<3;i++)
    75. {
    76. UART_SendString("Hello,World!");
    77. DelayMS(1);
    78. }
    79. asm(sleep);asm(nop);asm(nop);asm(nop);
    80. }
    81. }
    82. }
    83. //*****************************中断服务程序*****************************
    84. //进中断时间=1/(时钟源/xT/分频比)*(256-T0初值)
    85. void Intr(void) __interrupt 0
    86. {
    87. if(T0IF)
    88. {
    89. T0IF =0;
    90. T0 = 178;
    91. Count++;
    92. if(Count>=200)
    93. {
    94. Count=0;
    95. Time_1s=1; //1s时间到
    96. }
    97. }
    98. }
    1. #include "reg51.h"
    2. /*
    3. 将P1.0虚拟成串口发送脚TX
    4. 以9600bit/s的比特率向外发送数据
    5. 因为波特率是 9600bit/s
    6. 所以me发送一位的时间是 t=1000000us/9600=104us
    7. */
    8. sbit TX=P3^1; //P1^0 output TTL signal, need to transferred to rs232 signal, can be connected to P3^1
    9. #define u16 unsigned int //宏定义
    10. #define u8 unsigned char
    11. u8 sbuf;
    12. bit ti=0;
    13. void delay(u16 x)
    14. {
    15. while(x--);
    16. }
    17. void Timer0_Init()
    18. {
    19. TMOD |= 0x01;
    20. TH0=65440/256;
    21. TH0=65440%256;
    22. TR0=0;
    23. }
    24. void Isr_Init()
    25. {
    26. EA=1;
    27. ET0=1;
    28. }
    29. void Send_Byte(u8 dat)
    30. {
    31. sbuf=dat;//通过引入全局变量sbuf,可以保存形参dat
    32. TX=0; //A 起始位
    33. TR0=1;
    34. while(ti==0); //等待发送完成
    35. ti=0; //清除发送完成标志
    36. }
    37. void TF0_isr() interrupt 1 //每104us进入一次中断
    38. {
    39. static u8 i; //记录进入中断的次数
    40. TH0=65440/256;
    41. TL0=65440%256;
    42. i++;
    43. if(i>=1 && i<=8)
    44. {
    45. if((sbuf&(1<<(i-1)))==0) // (sbuf&(1<<(i-1)))表示取出i-1位
    46. {
    47. TX=0;
    48. }
    49. else
    50. {
    51. TX=1;
    52. }
    53. }
    54. if(i==9) //停止位
    55. {
    56. TX=1;
    57. }
    58. if(i==10)
    59. {
    60. TR0=0;
    61. i=0;
    62. ti=1; //发送完成
    63. }
    64. }
    65. void main()
    66. {
    67. TX=1; //使TX处于空闲状态
    68. Timer0_Init();
    69. Isr_Init();
    70. while(1)
    71. {
    72. Send_Byte(65); //0x41
    73. delay(60000);
    74. }
    75. }

    思路
    1>数据的发送其实就是控制发送引脚Ptxd的电平随着固定时序变化,那么固定的、周期性的时序需要一个定时器来产生。为了保证定时器周期高精度稳定可控,选用自动重装定时器模式 。为了尽可能的减少资源占用,发送和接收共用一个定时器资源
    2>程序的设计采用状态机设计模式,这样可以避免独占CPU,并且利于移植到各种状态机系统。状态迁移程序在ISR中实现
    3>定时器的中断频率为波特率的3倍[之所以这样做后面介绍接收时详述]。
    4>开启发送之后,ISR中发送相关程序得到执行,每3次中断处理1bit.根据时序,先产生bit0[起始位],然后根据8bit型数据依次在时序线上控制Ptxd的电平高低。数据位发送完毕后,若设置了校验位,则对8bits数据中bit1的数量进行判断,根据奇偶校验对bit1的数量通过控制Prxd的电平进行奇偶补全[发送数据位时对bit1进行计数]。然后根据设置发送对应长度的bit1[停止位]。最后,判断发送数据是否达到发送长度,若发送长度到达,则结束发送程序执行,否则继续循环发送
    5>开启接收之后,ISR中接收相关程序得到执行,并与发送程序互不干涉。首先每次中断都判断Prxd的电平是否置低[检测起始位],当检测到bit0之后,四个中断后进行数据位最低位的接收。这里之所以选择四个中断的延时,是因为当检测到bit0[起始位]的时刻,不管此时处于实际起始位的哪个时间点位置,四个中断后即下一次判断的位置总会是最接近一位数据中心那个点[一个bit中有三次中断点,有一个最接近中心,越接近中心越能免受发送与接收波特率不同步的影响,具体细节画图可知]。之后的每一位改为每三个中断进行一次判断处理[与波特率同步]。处理到校验位时,如果设置了奇偶校验,则对校验结果输出至设置好的校验标志位中,外围程序可根据此标准位判断是否校验出错。然后判断接收数据的长度是否达到设置长度,若没有,则等待至Prxd变为高电平后继续循环接收

    1. static void Xuart_isr(void) interrupt 3
    2. {
    3. Pts = ~Pts;
    4. if(++CNTisr == 3)
    5. {
    6. CNTisr = 0;
    7. /***************************SEND***************************/
    8. if(Fsend == SET)
    9. {
    10. switch(SEQsend)
    11. {
    12. // 起始位0:1bit
    13. case 0:
    14. Ptxd = LOW;
    15. SEQsend = 1;
    16. break;
    17. // 数据位SEND
    18. case 1:
    19. if((*ptr_send) & (1 << CNTsend_i))
    20. {
    21. CNTbit1++;
    22. Ptxd = HIGH;
    23. }
    24. else
    25. {
    26. Ptxd = LOW;
    27. }
    28. if(CNTsend_i >= 7)
    29. {
    30. CNTsend_i = 0;
    31. switch(Xuart_config.bit_parity)
    32. {
    33. case NONE: // 无校验
    34. SEQsend = 4;
    35. break;
    36. case ODD: // 奇校验
    37. SEQsend = 2;
    38. break;
    39. case EVEN: // 偶校验
    40. SEQsend = 3;
    41. break;
    42. default:
    43. SEQsend = 4;
    44. break;
    45. }
    46. }
    47. else{
    48. CNTsend_i++;
    49. }
    50. break;
    51. // 奇校验
    52. case 2:
    53. if((CNTbit1 % 2) == 0) // 偶数个1
    54. {
    55. Ptxd = HIGH;
    56. }
    57. else
    58. {
    59. Ptxd = LOW;
    60. }
    61. CNTbit1 = 0;
    62. SEQsend = 4;
    63. break;
    64. // 偶校验
    65. case 3:
    66. if((CNTbit1 % 2) == 0) // 偶数个1
    67. {
    68. Ptxd = LOW;
    69. }
    70. else
    71. {
    72. Ptxd = HIGH;
    73. }
    74. SEQsend = 4;
    75. break;
    76. // 停止位
    77. case 4:
    78. CNTbit1 = 0;
    79. switch(Xuart_config.bit_stop)
    80. {
    81. case S_1BIT:
    82. SEQsend = 5;
    83. break;
    84. case S_2BIT:
    85. if(++CNTstbit == 2)
    86. {
    87. CNTstbit = 0;
    88. SEQsend = 5;
    89. }
    90. break;
    91. default:
    92. //SEQsend = 5;
    93. break;
    94. }
    95. Ptxd = HIGH;
    96. break;
    97. // 下一帧or结束
    98. case 5:
    99. if(CNTsend_j >= len_send - 1) // 发送完毕处理
    100. {
    101. CNTsend_j = 0;
    102. Fsend_end = SET;
    103. Fsend = CLR;
    104. //TR1 = 0;
    105. }
    106. else
    107. {
    108. CNTsend_j++;
    109. ptr_send++;
    110. }
    111. SEQsend = 0;
    112. break;
    113. default:
    114. SEQsend = 0;
    115. CNTsend_i = 0;
    116. CNTsend_j = 0;
    117. CNTbit1 = 0;
    118. Fsend_end = SET;
    119. Fsend = CLR;
    120. TR1 = 0;
    121. }
    122. }
    123. }
    124. /**************************RECEIVE*************************/
    125. if(Freceive == SET)
    126. {
    127. switch(SEQreceive)
    128. {
    129. // 起始位bit0
    130. case 0:
    131. if(Prxd == LOW) // 收到起始位bit0
    132. {
    133. SEQreceive = 1;
    134. CNTrec = 0;
    135. break;
    136. }
    137. break;
    138. // 8bits_bit1数据
    139. case 1:
    140. if(++CNTrec == 4) // 第一次进来时为4个周期,提升容错率
    141. { // 其它时机进来为3个周期,保持同步性
    142. CNTrec = 1;
    143. if(Prxd == HIGH)
    144. {
    145. CNTbit1_++;
    146. *ptr_receive |= (U8)(1 << CNTreceive_i);
    147. }
    148. else
    149. {
    150. *ptr_receive &= (U8)(~(1 << CNTreceive_i));
    151. }
    152. if(CNTreceive_i >= 7) // 1帧接收完毕
    153. {
    154. CNTreceive_i = 0;
    155. CNTrec = 0;
    156. switch(Xuart_config.bit_parity)
    157. {
    158. case NONE: // 无校验
    159. SEQreceive = 4;
    160. break;
    161. case ODD: // 奇校验
    162. SEQreceive = 2;
    163. break;
    164. case EVEN: // 偶校验
    165. SEQreceive = 3;
    166. break;
    167. default:
    168. SEQreceive = 4;
    169. break;
    170. }
    171. }
    172. else
    173. {
    174. CNTreceive_i++;
    175. }
    176. }
    177. break;
    178. // 奇校验
    179. case 2:
    180. if(++CNTrec == 3) // 3个周期进入
    181. {
    182. CNTrec = 0;
    183. if((CNTbit1_ % 2) & (!Prxd)) // 校验正确
    184. {
    185. Freceive_parity = RIGHT;
    186. }
    187. else // 校验错误
    188. {
    189. Freceive_parity = ERROR;
    190. }
    191. CNTbit1_ = 0;
    192. SEQreceive = 4;
    193. break;
    194. }
    195. break;
    196. // 偶校验
    197. case 3:
    198. if(++CNTrec == 3) // 3个周期进入
    199. {
    200. CNTrec = 0;
    201. if((CNTbit1_ % 2) & (Prxd)) // 校验正确
    202. {
    203. Freceive_parity = RIGHT;
    204. }
    205. else // 校验错误
    206. {
    207. Freceive_parity = ERROR;
    208. }
    209. SEQreceive = 4;
    210. break;
    211. }
    212. break;
    213. // 帧结束
    214. case 4:
    215. if(Prxd == HIGH)
    216. {
    217. if(CNTreceive_j >= (len_receive - 1))
    218. {
    219. CNTreceive_j = 0;
    220. Freceive = CLR;
    221. Freceive_end = SET;
    222. }
    223. else
    224. {
    225. CNTreceive_j++;
    226. ptr_receive++;
    227. }
    228. SEQreceive = 0;
    229. break;
    230. }
    231. break;
    232. default:
    233. break;
    234. }
    235. }
    236. }