[关闭]
@richey 2022-10-27T01:40:31.000000Z 字数 25329 阅读 3208

物联网创新设计实践讲义-第二章-单片机软件设计实践

物联网创新设计实践 讲义 单片机软件设计实践

2.1 基于协作式调度的单片机软件设计基础

2.1.1 C51基础

https://www.zybuluo.com/richey/note/1262297

2.1.2 中断系统、定时/计数器

https://www.zybuluo.com/richey/note/1263469

2.1.3 协作式调度器

2.1.3.1 考虑这样一个常见的系统
2.1.3.2 经典方法:前后台系统(超级循环)

2.1.3.4 协作式调度器

  1. #include <reg51.h>
  2. #include "common.h"
  3. #define FOSC 11059200ul
  4. #define T0_H (65536-(10*FOSC)/(12*1000))/256
  5. #define T0_L (65536-(10*FOSC)/(12*1000))%256
  6. uint16_t tick = 0;
  7. bit bFlag1 = 0;
  8. bit bFlag2 = 0;
  9. bit bFlag3 = 0;
  10. bit bFlag4 = 0;
  11. void initSys();
  12. sbit LED0 = P1^0;
  13. sbit LED1 = P1^1;
  14. sbit LED2 = P1^2;
  15. sbit LED3 = P1^3;
  16. void main(){
  17. initSys();
  18. while(TRUE){
  19. if(bFlag1){
  20. bFlag1 = 0;
  21. LED0 = !LED0;
  22. }
  23. if(bFlag2){
  24. bFlag2 = 0;
  25. LED1 = !LED1;
  26. }
  27. if(bFlag3){
  28. bFlag3 = 0;
  29. LED2 = !LED2;
  30. }
  31. if(bFlag4){
  32. bFlag4 = 0;
  33. LED3 = !LED3;
  34. }
  35. }
  36. }
  37. void initSys(){
  38. TMOD = 0x01;
  39. TH0 = T0_H;
  40. TL0 = T0_L;
  41. EA = 1;
  42. ET0 = 1;
  43. TR0 = 1;
  44. }
  45. void timer0() interrupt 1 {
  46. TH0 = T0_H;
  47. TL0 = T0_L;
  48. tick++;
  49. if((tick % 100) == 0){
  50. bFlag1 = 1;
  51. }
  52. if((tick % 150) == 3){
  53. bFlag2 = 1;
  54. }
  55. if((tick % 20) == 5){
  56. bFlag3 = 1;
  57. }
  58. if((tick % 300) == 7){
  59. bFlag4 = 1;
  60. }
  61. }

2.1.3.6 课堂作业

2.2 AD转换及数字电压表应用综合实例

image.png-62.5kB

2.2.1 数码管驱动程序设计:固定显示“2022”

Created with Raphaël 2.1.2定时器0中断入口重装TH0、TL0b5MsFlag := 1;中断返回
Created with Raphaël 2.1.2开始调用定时器初始化子程序 b5MsFlag == 1?b5MsFlag := 0;P3口输出字形码;i == 0?COM0-COM3输出0111;i++;i >= 4?i:=0;i == 1?COM0-COM3输出1011;i == 2?COM0-COM3输出1101;i == 3?COM0-COM3输出1110;yesnoyesnoyesnoyesnoyesnoyesno
Created with Raphaël 2.1.2开始设置TMOD工作方式TH0、TL0赋初值;开中断;启动定时器;返回
  1. #include "reg51.h"
  2. #include "common.h"
  3. #define FOSC 11059200ul
  4. #define T0_H (65536-(5*FOSC)/(1000*12))/256
  5. #define T0_L (65536-(5*FOSC)/(1000*12))%256
  6. sbit COM0 = P1^0;
  7. sbit COM1 = P1^1;
  8. sbit COM2 = P1^2;
  9. sbit COM3 = P1^3;
  10. uint8_t dispBuf[] = {1,2,3,4};
  11. uint8_t code ledDeg[] = {0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82,0xF8, 0x80, 0x90};
  12. bit segFlag = 0;
  13. uint16_t counts = 0;
  14. void initSys();
  15. void updateSeg();
  16. void main(){
  17. initSys();
  18. while(1){
  19. if(segFlag){
  20. segFlag = 0;
  21. updateSeg();
  22. }
  23. }
  24. }
  25. void initSys(){
  26. TMOD = 0x01;
  27. TH0 = T0_H;
  28. TL0 = T0_L;
  29. EA = 1;
  30. ET0 = 1;
  31. TR0 = 1;
  32. }
  33. void timer0() interrupt 1{
  34. TH0 = T0_H;
  35. TL0 = T0_L;
  36. segFlag = 1;
  37. if(counts++ > 200){
  38. counts = 0;
  39. b1sFlag = 1;
  40. }
  41. }
  42. void updateSeg(){
  43. static uint8_t i = 0;
  44. P3 = 0xff; //proteus simulation need
  45. switch(i){
  46. case 0: COM0 = 1; COM1 = 0; COM2 = 0; COM3 = 0; break;
  47. case 1: COM0 = 0; COM1 = 1; COM2 = 0; COM3 = 0; break;
  48. case 2: COM0 = 0; COM1 = 0; COM2 = 1; COM3 = 0; break;
  49. case 3: COM0 = 0; COM1 = 0; COM2 = 0; COM3 = 1; break;
  50. }
  51. P3 = ledDeg[dispBuf[i]];
  52. i++;
  53. if(i >= 4){
  54. i = 0;
  55. }
  56. }
Created with Raphaël 2.1.2定时器0中断入口重装TH0、TL0b5MsFlag := 1;counter++;counter > 200?b1SFlag :=1;中断返回yesno
Created with Raphaël 2.1.2开始调用定时器初始化子程序 b5MsFlag == 1?b5MsFlag := 0;P3口输出字形码;i == 0?COM0-COM3输出0111;i++;i >= 4?i:=0;i == 1?COM0-COM3输出1011;i == 2?COM0-COM3输出1101;i == 3?COM0-COM3输出1110;yesnoyesnoyesnoyesnoyesnoyesno

2.1.2 数码管显示从0000-9999的变化数据

  1. #include "reg51.h"
  2. #include "common.h"
  3. #define FOSC 11059200ul
  4. #define T0_H (65536-(5*FOSC)/(1000*12))/256
  5. #define T0_L (65536-(5*FOSC)/(1000*12))%256
  6. sbit COM0 = P1^0;
  7. sbit COM1 = P1^1;
  8. sbit COM2 = P1^2;
  9. sbit COM3 = P1^3;
  10. uint16_t dispData = 4567;
  11. uint8_t dispBuf[] = {1,2,3,4};
  12. uint8_t code ledDeg[] = {0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82,0xF8, 0x80, 0x90};
  13. bit segFlag = 0;
  14. bit b1sFlag = 0;
  15. uint16_t counts = 0;
  16. void initSys();
  17. void updateSeg();
  18. void updateDispBuf();
  19. void main(){
  20. initSys();
  21. while(1){
  22. if(segFlag){
  23. segFlag = 0;
  24. updateSeg();
  25. }
  26. if(b1sFlag){
  27. b1sFlag = 0;
  28. if(dispData++ > 9999){
  29. dispData = 0;
  30. }
  31. updateDispBuf();
  32. }
  33. }
  34. }
  35. void initSys(){
  36. TMOD = 0x01;
  37. TH0 = T0_H;
  38. TL0 = T0_L;
  39. EA = 1;
  40. ET0 = 1;
  41. TR0 = 1;
  42. }
  43. void timer0() interrupt 1{
  44. TH0 = T0_H;
  45. TL0 = T0_L;
  46. segFlag = 1;
  47. if(counts++ > 200){
  48. counts = 0;
  49. b1sFlag = 1;
  50. }
  51. }
  52. void updateDispBuf(){
  53. uint8_t i;
  54. uint16_t tmp = dispData;
  55. for(i = 0; i < 4 ;i++){
  56. dispBuf[3-i] = tmp%10;
  57. tmp = tmp/10;
  58. }
  59. }
  60. void updateSeg(){
  61. static uint8_t i = 0;
  62. P3 = 0xff; //proteus simulation need
  63. switch(i){
  64. case 0: COM0 = 1; COM1 = 0; COM2 = 0; COM3 = 0; break;
  65. case 1: COM0 = 0; COM1 = 1; COM2 = 0; COM3 = 0; break;
  66. case 2: COM0 = 0; COM1 = 0; COM2 = 1; COM3 = 0; break;
  67. case 3: COM0 = 0; COM1 = 0; COM2 = 0; COM3 = 1; break;
  68. }
  69. P3 = ledDeg[dispBuf[i]];
  70. i++;
  71. if(i >= 4){
  72. i = 0;
  73. }
  74. }

2.2.3 AD转换程序设计

2.2.3.1 Tl549串行AD转换芯片

image.png-209.9kB
image.png-53.2kB
image.png-60kB

2.2.3.2 AD转换程序设计

image.png-651.8kB
image.png-37.1kB

  1. sbit TLC549_CS = P1^0;
  2. sbit TLC549_DOUT = P1^1;
  3. sbit TLC549_CLK = P1^6;
  4. uint8_t bdata AdValue;
  5. sbit AIN = AdValue^0;
  6. uint8_t getAdValue(){
  7. uchar i;
  8. TLC549_CS = 0;
  9. TLC549_DOUT = 1;
  10. TLC549_CLK = 0;
  11. for(i=0;i<8;i++){
  12. AdValue = AdValue<<1;
  13. TLC549_CLK = 1;
  14. _nop_();
  15. _nop_();
  16. AIN = TLC549_DOUT;
  17. TLC549_CLK = 0;
  18. _nop_();
  19. _nop_();
  20. }
  21. TLC549_CS = 1;
  22. return AdValue;
  23. }

2.2.4 标度变换

  1. if(adFlag){
  2. adFlag = 0;
  3. dispValue = 100*((float)getAdValue()*5.0/255.0);
  4. }

2.2.5 数字电压表软件设计

image.png-32.3kB
image.png-39.3kB

  1. #include <reg51.h>
  2. #include <intrins.h>
  3. #include "common.h"
  4. #define FOSC 11059200ul
  5. #define T0_H (65536-(2*FOSC)/(1000*12))/256
  6. #define T0_L (65536-(2*FOSC)/(1000*12))%256
  7. sbit COM0 = P1^0;
  8. sbit COM1 = P1^1;
  9. sbit COM2 = P1^2;
  10. sbit COM3 = P1^3;
  11. sbit TLC549_CS = P1^6;
  12. sbit TLC549_DOUT = P1^5;
  13. sbit TLC549_CLK = P1^7;
  14. bit flag = 0;
  15. bit flag1 = 0;
  16. uint8_t ADcounts = 0;
  17. uint8_t dispBuf[] = {2,0,1,8};
  18. uint8_t code ledDeg[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90};
  19. uint8_t bdata AdValue;
  20. sbit AIN = AdValue^0;
  21. void initSys();
  22. uint8_t getAdValue(){
  23. uint8_t i;
  24. TLC549_CS = 0;
  25. TLC549_DOUT = 1;
  26. TLC549_CLK = 0;
  27. for(i=0;i<8;i++){
  28. AdValue = AdValue<<1;
  29. TLC549_CLK = 1;
  30. _nop_();
  31. _nop_();
  32. AIN = TLC549_DOUT;
  33. TLC549_CLK = 0;
  34. _nop_();
  35. _nop_();
  36. }
  37. TLC549_CS = 1;
  38. return AdValue;
  39. }
  40. void main(){
  41. uint8_t i = 0;
  42. uint8_t j = 0;
  43. uint8_t ucAdValue=0;
  44. uint16_t uiAdValue =0;
  45. float fAdValue = 0.0;
  46. initSys();
  47. while(1){
  48. if(flag1){
  49. flag1 = 0;
  50. ucAdValue = getAdValue();
  51. fAdValue = (float)(ucAdValue*(5.0/255.0));
  52. uiAdValue= fAdValue * 1000;
  53. for(j=0;j<4;j++){
  54. dispBuf[3-j]= uiAdValue%10;
  55. uiAdValue /=10;
  56. }
  57. }
  58. if(flag)
  59. {
  60. flag = 0;
  61. switch(i){
  62. case 0:
  63. COM0=0;COM1=1;COM2=1;COM3=1;
  64. break;
  65. case 1:
  66. COM0=1;COM1=0;COM2=1;COM3=1;
  67. break;
  68. case 2:
  69. COM0=1;COM1=1;COM2=0;COM3=1;
  70. break;
  71. case 3:
  72. COM0=1;COM1=1;COM2=1;COM3=0;
  73. break;
  74. }
  75. P3 = 0xff;
  76. P3 = ledDeg[dispBuf[i]];
  77. if(i==0)
  78. P3 &= 0x7f;
  79. if(++i>=4){
  80. i=0;
  81. }
  82. }
  83. }
  84. }
  85. void initSys(){
  86. TMOD &= 0xF0;
  87. TMOD |= 0x01;
  88. EA = 1;
  89. ET0 =1;
  90. TH0 = T0_H;
  91. TL0 = T0_L;
  92. TR0 = 1;
  93. }
  94. void timer0ISR()interrupt 1{
  95. TH0 = T0_H;
  96. TL0 = T0_L;
  97. flag = 1;
  98. if(ADcounts++>=40){
  99. ADcounts = 0;
  100. flag1 = 1;
  101. }
  102. }

2.2.6 基于“小小调度器”的数字电压表软件设计

2.2.6.1 小小调度器

在本节之前,我们按照协作式调度器的设计思想,通过定时器中断产生时标,在主循环中查询标志为实现驱动不同频度的周期性任务。这种方法需要我们设计不同的flag标志,配合时钟tick计数器完成,那么有没有便捷的方法实现以上功能呢?
答案是操作系统(OS)的思想,其核心是一个任务调度器,可以将不同的任务按照设计需要进行调度。实现一个单片机可用的操作系统相当复杂,同学们可以阅读一下相关的资料,比如usos/II、tiny51等嵌入式操作系统相关的文献。这些操作系统占用系统资源(RAM、ROM、CPU)较多,在51单片机上面使用受限,其学习也相对复杂。本节,我们学习一个轻量级的调度器:“小小调度器”,并应用于数字电压表软件设计。

原作者smset:
小小调度器16位版本 小小调度器 V1.1 设计原理 (讨论稿) By smset
前言:
小小调度器是一款基于 C 语言的,协作式多任务编程框架。它基于状态机原理实现,所有任务 均采用公共堆栈,具有简单小巧,易于移植的特点,非常适合于资源紧张的单片机编程使用。 小小调度器的多任务并行机制和传统的状态机的并行机制原理是想通的。

主要的区别在于:小小调度器利用了 C 语言的LINE宏,这个LINE宏,代表了源文件中 代码的行号,通过将代码行号保存到静态变量的方式,来记录程序运行的位置信息,从而使得 原来需要人工实现的状态值设计、状态变量赋值以及状态跳转的系列编程工作,大部分均由记 录行号的宏自动实现了,使得开发者可以节省很多底层的状态设计和处理的编程工作。 基于此核心原理,小小调度器设计了一个框架和宏定义,以极低的 CPU 资源代价,模拟了一个 和真实 RTOS 系统相似的多任务编程环境,使得编程者可以用更自然、更优雅、更易于理解的方 式,来编写多任务并行代码,把时间和精力,更多的放在应用业务层逻辑的代码实现上。
特点

  1. #include <stc89c51.h>
  2. /****小小调度器开始**********************************************/
  3. #define MAXTASKS 3
  4. volatile unsigned char timers[MAXTASKS];
  5. #define _SS \
  6. static unsigned char _lc = 0; \
  7. switch (_lc) { \
  8. default:
  9. #define _EE \
  10. ; \
  11. } \
  12. ; \
  13. _lc = 0; \
  14. return 255;
  15. #define WaitX(tickets) \
  16. do { \
  17. _lc = (__LINE__ % 255) + 1; \
  18. return tickets; \
  19. } while (0); \
  20. case (__LINE__ % 255) + 1:
  21. #define RunTask(TaskName, TaskID) \
  22. do { \
  23. if (timers[TaskID] == 0) \
  24. timers[TaskID] = TaskName(); \
  25. } while (0);
  26. #define RunTaskA(TaskName, TaskID) \
  27. { \
  28. if (timers[TaskID] == 0) { \
  29. timers[TaskID] = TaskName(); \
  30. continue; \
  31. } \
  32. } //前面的任务优先保证执行
  33. #define CallSub(SubTaskName) \
  34. do { \
  35. unsigned char currdt; \
  36. _lc = (__LINE__ % 255) + 1; \
  37. return 0; \
  38. case (__LINE__ % 255) + 1: \
  39. currdt = SubTaskName(); \
  40. if (currdt != 255) \
  41. return currdt; \
  42. } while (0);
  43. #define InitTasks() \
  44. { \
  45. unsigned char i; \
  46. for (i = MAXTASKS; i > 0; i--) \
  47. timers[i - 1] = 0; \
  48. }
  49. #define UpdateTimers() \
  50. { \
  51. unsigned char i; \
  52. for (i = MAXTASKS; i > 0; i--) { \
  53. if ((timers[i - 1] != 0) && (timers[i - 1] != 255)) \
  54. timers[i - 1]--; \
  55. } \
  56. }
  57. #define SEM unsigned int
  58. //初始化信号量
  59. #define InitSem(sem) sem = 0;
  60. //等待信号量
  61. #define WaitSem(sem) \
  62. do { \
  63. sem = 1; \
  64. WaitX(0); \
  65. if (sem > 0) \
  66. return 1; \
  67. } while (0);
  68. //等待信号量或定时器溢出, 定时器tickets 最大为0xFFFE
  69. #define WaitSemX(sem, tickets) \
  70. do { \
  71. sem = tickets + 1; \
  72. WaitX(0); \
  73. if (sem > 1) { \
  74. sem--; \
  75. return 1; \
  76. } \
  77. } while (0);
  78. //发送信号量
  79. #define SendSem(sem) \
  80. do { \
  81. sem = 0; \
  82. } while (0);
  83. /*****小小调度器结束*******************************************************/
  84. sbit LED1 = P2 ^ 1;
  85. sbit LED2 = P2 ^ 2;
  86. sbit LED0 = P2 ^ 5;
  87. unsigned char task0() {
  88. _SS while (1) {
  89. WaitX(50);
  90. LED0 = !LED0;
  91. }
  92. _EE
  93. }
  94. unsigned char task1() {
  95. _SS6 while (1) {
  96. WaitX(100);
  97. LED1 = !LED1;
  98. }
  99. _EE
  100. }
  101. unsigned char task2() {
  102. _SS while (1) {
  103. WaitX(100);
  104. LED2 = !LED2;
  105. }
  106. _EE
  107. }
  108. void InitT0() {
  109. TMOD = 0x21;
  110. IE |= 0x82;
  111. TL0 = 0Xff;
  112. TH0 = 0XDB;
  113. TR0 = 1;
  114. }
  115. void INTT0(void) interrupt 1 using 1 {
  116. TL0 = 0Xff; // 10ms 重装
  117. TH0 = 0XDB;
  118. UpdateTimers();
  119. RunTask(task0, 0); //任务0具有精确按时获得执行的权限,要求:task0每次执行消耗时间<0.5个
  120. //ticket
  121. }
  122. void main() {
  123. InitT0();
  124. InitTasks(); //初始化任务,实际上是给timers清零
  125. while (1) {
  126. // RunTask(task0,0);
  127. RunTaskA(task1, 1); //任务1具有比任务2高的运行权限
  128. RunTaskA(task2, 2); //任务2具有低的运行权限
  129. }
  130. }
  131. 复制代码

2.2.6.2 基于“小小调度器”的数字电压表软件设计

  1. //xxsch.h
  2. #ifndef __XXSCH_H
  3. #define __XXSCH_H
  4. #define MAXTASKS 16
  5. #define BITS 16
  6. #define SEM unsigned int
  7. #if (BITS==8)
  8. #define TASK unsigned char
  9. #define TICKET_MAX 0xFF
  10. #endif
  11. #if (BITS==16)
  12. #define TASK unsigned short
  13. #define TICKET_MAX 0xFFFF
  14. #endif
  15. #if (BITS==32)
  16. #define TASK unsigned long
  17. #define TICKET_MAX 0xFFFFFFFF
  18. #endif
  19. #define _SS static unsigned char _lc=0; switch(_lc){default:
  20. #define _EE ;}; _lc=0; return TICKET_MAX;
  21. #define WaitX(tickets) do { _lc=(__LINE__%255)+1; return (tickets) ;case (__LINE__%255)+1:;} while(0);
  22. #define WaitUntil(A) do { while(!(A)) WaitX(1);} while(0);
  23. #define WAITUNTIL(A,VAL) do { WaitX(1);} while((A)!=VAL);
  24. #define WaitUntilR(A) do { while(!(A)) WaitX(0);} while(0);
  25. #define WAITUNTILR(A,VAL) do { WaitX(0);} while((A)!=VAL);
  26. #define RunTask(TaskName,TaskID) do { if (timers[TaskID]==0) { TASK d=TaskName(); while(timers[TaskID]!=d) timers[TaskID]=d;} } while(0);
  27. #define RunTaskA(TaskName,TaskID) do { if (timers[TaskID]==0) {TASK d=TaskName(); while(timers[TaskID]!=d) timers[TaskID]=d; continue;} }while(0);
  28. #define CallSub(SubTaskName) do {TASK currdt; _lc=(__LINE__%255)+1; return 0; case (__LINE__%255)+1: currdt=SubTaskName(); if(currdt!=TICKET_MAX) return currdt;} while(0);
  29. #define CallSub1(SubTaskName,p1) do {TASK currdt; _lc=(__LINE__%255)+1; return 0; case (__LINE__%255)+1: currdt=SubTaskName(p1); if(currdt!=TICKET_MAX) return currdt;} while(0);
  30. #define CallSub2(SubTaskName,p1,p2) do {TASK currdt; _lc=(__LINE__%255)+1; return 0; case (__LINE__%255)+1: currdt=SubTaskName(p1,p2); if(currdt!=TICKET_MAX) return currdt;} while(0);
  31. #define InitTasks() do {unsigned char i; for(i=MAXTASKS;i>0 ;i--) timers[i-1]=0; } while(0);
  32. #define UpdateTimers() do{unsigned char i; for(i=MAXTASKS;i>0 ;i--){if((timers[i-1]!=0)&&(timers[i-1]!=TICKET_MAX)) timers[i-1]--;}} while(0);
  33. #define InitSem(sem) do{sem=0;}while(0);
  34. #define WaitSem(sem) do{ sem=1; WaitX(0); if (sem>0) return 1;} while(0);
  35. #define SendSem(sem) do {sem=0;} while(0);
  36. #define WaitSemX(sem, tickets) do{sem=tickets+1;WaitX(0);if(sem>1){sem--;return 1;}}while (0);
  37. #endif
  1. //main.h
  2. #ifndef __MAIN_H
  3. #define __MAIN_H
  4. #include "STC15Fxxxx.h"
  5. #define OSC_FREQ (11059200UL)
  6. #define OSC_PER_INST (12)
  7. #define BAUD 9600
  8. #define T1_H (256-OSC_FREQ/12/32/BAUD)
  9. #define T0_H (65536-(5*OSC_FREQ)/(1000*12))/256
  10. #define T0_L (65536-(5*OSC_FREQ)/(1000*12))%256
  11. typedef unsigned char uint8_t;
  12. typedef unsigned int uint16_t;
  13. typedef unsigned long uint32_t;
  14. typedef char int8_t;
  15. typedef int int16_t;
  16. typedef long int32_t;
  17. // Misc #defines
  18. #ifndef TRUE
  19. #define FALSE 0
  20. #define TRUE (!FALSE)
  21. #endif
  22. #include "xxsch.h"
  23. #endif
  1. //main.c
  2. #include "main.h"
  3. #include "adc.h"
  4. #include "ledseg.h"
  5. #include "xxsch.h"
  6. #include "key.h"
  7. volatile TASK timers[MAXTASKS];
  8. //TASK ledseg_task();
  9. //TASK adc_task();
  10. TASK update_disp_buf_task();
  11. float g_temperature = 25.2;
  12. float g_humidity = 57.3;
  13. float g_voltage = 3.234;
  14. extern void update_ledseg_buf(float dispData, uint8_t pointsNum);
  15. void initSys();
  16. extern uint8_t key_value;
  17. void main(void) {
  18. initSys();
  19. InitTasks();
  20. while (1) {
  21. RunTaskA(ledseg_task, 8);
  22. RunTaskA(adc_task, 6);
  23. RunTaskA(key_scan_task, 2);
  24. RunTaskA(update_disp_buf_task, 4);
  25. }
  26. }
  27. void initSys() {
  28. TMOD = 0x21;
  29. TH0 = T0_H;
  30. TL0 = T0_L;
  31. TH1 = T1_H;
  32. TL1 = T1_H;
  33. EA = 1;
  34. ET0 = 1;
  35. SCON = 0x50;
  36. EA = 1;
  37. ET0 = 1;
  38. ES = 1;
  39. TR0 = 1;
  40. TR1 = 1;
  41. }
  42. void timer0_isr(void) interrupt 1 using 1 {
  43. TL0 = T0_L;
  44. TH0 = T0_H;
  45. UpdateTimers();
  46. }
  47. void update_disp_buf() {
  48. switch (key_value) {
  49. case 0:
  50. update_ledseg_buf(g_voltage, 3);
  51. break;
  52. case 1:
  53. update_ledseg_buf(g_temperature, 1);
  54. break;
  55. case 2:
  56. update_ledseg_buf(g_humidity, 1);
  57. break;
  58. }
  59. }
  60. TASK update_disp_buf_task() {
  61. _SS while (1) {
  62. WaitX(100);
  63. update_disp_buf();
  64. }
  65. _EE
  66. }
  1. //port.h
  2. #ifndef __PORT_H
  3. #define __PORT_H
  4. // ------ ledseg.c------------------------------------------------
  5. // LED connection requires 12 port pins
  6. #define LED_DATA_PORT (P2)
  7. /* Connections to LED_DATA_PORT - See Figure 21.6 for details
  8. DP G F E D C B A = LED display pins
  9. | | | | | | | |
  10. x.7 x.6 x.5 x.4 x.3 x.2 x.1 x.0 = Port pins
  11. x.7 == LED_DATA_PORT^7, etc
  12. LED codes (NB - positive logic assumed here)
  13. 0 = abcdef => 00111111 = 0x3F
  14. 1 = bc => 00000110 = 0x06
  15. 2 = abdeg => 01011011 = 0x5B
  16. 3 = abcdg => 01001111 = 0x4F
  17. 4 = bcfg => 01100110 = 0x66
  18. 5 = acdfg => 01101101 = 0x6D
  19. 6 = acdefg => 01111101 = 0x7D
  20. 7 = abc => 00000111 = 0x07
  21. 8 = abcdefg => 01111111 = 0x7F
  22. 9 = abcdfg => 01101111 = 0x6F
  23. To display decimal point, add 10 (decimal) to the above values */
  24. // Any combination of (4) pins on any ports may be used here
  25. sbit LED_DIGIT_0 = P1^0;
  26. sbit LED_DIGIT_1 = P1^1;
  27. sbit LED_DIGIT_2 = P1^2;
  28. sbit LED_DIGIT_3 = P1^3;
  29. #endif
  1. //ledseg.c
  2. #include "main.h"
  3. #include "port.h"
  4. #include "ledseg.h"
  5. // ------ Public variable definitions ------------------------------
  6. // Lookup table - stored in code area
  7. // See Port.H for connections and code details
  8. uint8_t code LED_Table_G[20] =
  9. // 0 1 2 3 4 5 6 7 8 9
  10. {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F,
  11. // 0. 1. 2. 3. 4. 5. 6. 7. 8. 9.
  12. 0xBF, 0x86, 0xDB, 0xCF, 0xE6, 0xED, 0xFD, 0x87, 0xFF, 0xEF};
  13. // Global data formatted for display (initially 0,0,0,0)
  14. uint8_t LED_Mx4_Data_G[4] = {0x3F,0x3F,0x3F,0x3F};
  15. uint8_t idata point_pos = 0;
  16. static uint8_t idata Digit_G;
  17. void update_ledseg(void)
  18. {
  19. //only proteus simulation need the following line!!!
  20. LED_DATA_PORT = 0xff;
  21. // Increment the digit to be displayed
  22. if (++Digit_G == LED_NUM_DIGITS)
  23. {
  24. Digit_G = 0;
  25. }
  26. // Allows any pins to be used
  27. switch (Digit_G)
  28. {
  29. case 0:
  30. {
  31. LED_DIGIT_0 = 0;
  32. LED_DIGIT_1 = 0;
  33. LED_DIGIT_2 = 0;
  34. LED_DIGIT_3 = 1;
  35. break;
  36. }
  37. case 1:
  38. {
  39. LED_DIGIT_0 = 0;
  40. LED_DIGIT_1 = 0;
  41. LED_DIGIT_2 = 1;
  42. LED_DIGIT_3 = 0;
  43. break;
  44. }
  45. case 2:
  46. {
  47. LED_DIGIT_0 = 0;
  48. LED_DIGIT_1 = 1;
  49. LED_DIGIT_2 = 0;
  50. LED_DIGIT_3 = 0;
  51. break;
  52. }
  53. case 3:
  54. {
  55. LED_DIGIT_0 = 1;
  56. LED_DIGIT_1 = 0;
  57. LED_DIGIT_2 = 0;
  58. LED_DIGIT_3 = 0;
  59. }
  60. }
  61. LED_DATA_PORT = 255 - LED_Mx4_Data_G[Digit_G];
  62. if(Digit_G == (point_pos) && Digit_G !=0){
  63. LED_DATA_PORT &= 0x7f;
  64. }
  65. }
  66. void update_ledseg_buf(float dispData, uint8_t pointsNum){
  67. uint16_t u16Value;
  68. uint8_t j;
  69. switch(pointsNum){
  70. case 0:
  71. u16Value = (uint16_t)dispData;
  72. break;
  73. case 1:
  74. u16Value = (uint16_t)(dispData * 10);
  75. break;
  76. case 2:
  77. u16Value = (uint16_t)(dispData *100);
  78. break;
  79. case 3:
  80. u16Value = (uint16_t)(dispData *1000);
  81. break;
  82. }
  83. for( j=0;j<4;j++){
  84. LED_Mx4_Data_G[j]= LED_Table_G[u16Value%10];
  85. u16Value /=10;
  86. }
  87. point_pos = pointsNum;
  88. }
  89. TASK ledseg_task() {
  90. _SS while (1) {
  91. WaitX(1);
  92. update_ledseg();
  93. }
  94. _EE
  95. }
  1. //adc.c
  2. #include "Main.h"
  3. #include "Port.h"
  4. #include <intrins.h>
  5. #include "adc.h"
  6. sbit TLC549_DOUT = P1 ^ 5;
  7. sbit TLC549_CS = P1 ^ 6;
  8. sbit TLC549_CLK = P1 ^ 7;
  9. uint8_t bdata ad_value;
  10. sbit AIN = ad_value ^ 0;
  11. extern updateLed(float dispData, uint8_t pointsNum);
  12. extern float g_voltage;
  13. // uint8_t current_ad_value;
  14. uint8_t tlc549_adc() {
  15. uint8_t i;
  16. TLC549_CS = 0;
  17. TLC549_DOUT = 1;
  18. TLC549_CLK = 0;
  19. for (i = 0; i < 8; i++) {
  20. ad_value = ad_value << 1;
  21. TLC549_CLK = 1;
  22. _nop_();
  23. _nop_();
  24. AIN = TLC549_DOUT;
  25. TLC549_CLK = 0;
  26. _nop_();
  27. _nop_();
  28. }
  29. TLC549_CS = 1;
  30. return ad_value;
  31. }
  32. void get_ad(void) {
  33. uint8_t value;
  34. value = tlc549_adc();
  35. g_voltage = (float)(value * (5.0 / 255.0));
  36. }
  37. TASK adc_task() {
  38. _SS while (1) {
  39. WaitX(20);
  40. get_ad();
  41. }
  42. _EE
  43. }
  1. //key.c
  2. #include "main.h"
  3. #include "key.h"
  4. sbit KEY1 = P3 ^ 5;
  5. uint8_t key_value = 0;
  6. void key_scan() ;
  7. TASK key_scan_task() {
  8. _SS while (1) {
  9. WaitX(5);
  10. key_scan();
  11. }
  12. _EE
  13. }
  14. static void key_scan() {
  15. static uint8_t _status = 0;
  16. switch (_status) {
  17. case 0:
  18. if (KEY1 == 0) {
  19. _status = 1;
  20. }
  21. break;
  22. case 1:
  23. if (KEY1 == 0) {
  24. _status = 2;
  25. } else {
  26. _status = 0;
  27. }
  28. break;
  29. case 2:
  30. if (KEY1 == 1) {
  31. _status = 3;
  32. }
  33. break;
  34. case 3:
  35. if (KEY1 == 1) {
  36. _status = 0;
  37. if (++key_value >= 3) {
  38. key_value = 0;
  39. }
  40. } else {
  41. _status = 0;
  42. }
  43. break;
  44. }
  45. }

2.3 串口通信协议设计

2.3.1 串行通信与UART

2.3.1.1 串行通信的种类

2.3.1.2. 波特率

2.3.1.3 串行通信数据的传输方向

2.3.1.4 串行通信接口的种类

2.3.2 MCS-51单片机的串行口

image_1cnlmv75a1fb14dm152e4j38an4d.png-125.1kB

2.3.2.1 串行通信接口控制寄存器SCON

SM0 SM1 方式 功 能 说 明
0 0 0 同步移位寄存器方式(用于扩展I/O口)
0 1 1 8位异步收发,波特率可变(由定时器控制)
1 0 2 9位异步收发,波特率为fosc/64或fosc/32
1 1 3 9位异步收发,波特率可变(由定时器控制)

2.3.2.2 特殊功能寄存器PCON(波特率倍增SMOD)

image.png-49.2kB

2.3.2.3 串口工作方式

2.3.2.3.1 方式0:同步方式

同步移位寄存器输入/输出方式,常用于外接移位寄存器,以扩展并行I/O口。8位数据为一帧,不设起始位和停止位,先发送或接收最低位。波特率固定为fosc/12。帧格式如下:
image_1cnlo4ndq193k1lom1oov14nc1pv48g.png-10.2kB
image_1cnlo5bii8tfmhsdsp1kkhbso8t.png-76.3kB

2.3.2.3.2 方式1:8位异步方式(最常用)
2.3.2.3.3 方式2:9位异步方式
2.3.2.3.3 方式2:9位异步方式(波特率不可调)

2.3.2.4 波特率

2.3.3 串口驱动程序设计

  1. #define FOSC 11059200ul
  2. #define BAUD 9600
  3. #define T1_H 256-FOSC/12/32/BAUD
  4. #define T1_L 256-FOSC/12/32/BAUD
  5. #define T0_H (65536-(FOSC*50)/(12*1000))/256
  6. #define T0_L (65536-(FOSC*50)/(12*1000))%256
  7. void initSys(){
  8. SCON = 0x50; //8位异步方式,允许接收
  9. TMOD = 0x21; //T0方式1,T1方式2
  10. TH1 = T1_H;
  11. TL1 = T1_L;
  12. TH0 = T0_H;
  13. TL0 = T0_L;
  14. EA = 1;
  15. ET0 = 1;
  16. ES = 1;
  17. TR0 = 1;
  18. TR1 = 1;
  19. }
  1. //串口查询方式发送1个字节数据
  2. void SendChar(uint8_t u8Data){
  3. SBUF = u8Data; //启动发送(注意串口是低速设备,只是启动发送并没有发送完成!)
  4. while(!TI);//等待发送完成
  5. TI = 0; //只要执行到此处,说明发送完成了(TI为1),将TI清零以免下次无法发送。
  6. }
  7. uint8_t buf;
  8. bit bRecvFalg = 0 ;
  9. //中断方式接收
  10. void serialIsr() interrupt 4{
  11. if(RI){ //如果是接收引起的中断执行这里
  12. RI = 0//手工清零
  13. buf = SBUF;
  14. bRecvFalg = 1;//置接收标志为1
  15. }
  16. }
  1. #include <reg51.h>
  2. #include "common.h"
  3. #define FOSC 11059200ul
  4. #define BAUD 9600
  5. #define T1_H 256-FOSC/12/32/BAUD
  6. #define T1_L 256-FOSC/12/32/BAUD
  7. #define T0_H (65536-(50*FOSC)/(12*1000))/256
  8. #define T0_L (65536-(50*FOSC)/(12*1000))%256
  9. bit b1sFlag = 0;
  10. bit bRecvFlag = 0;
  11. uint8_t u8SendData[]="Hello MCS-51\r\n";
  12. void SendChar(uint8_t u8Data);
  13. void initSys();
  14. void main(){
  15. uint8_t i;
  16. initSys();
  17. while(1){
  18. if(b1sFlag){
  19. b1sFlag = 0;
  20. for(i=0;i<(sizeof(u8SendData)-1);i++){
  21. SendChar(u8SendData[i]);
  22. }
  23. }
  24. if(bRecvFlag){
  25. bRecvFlag= 0;
  26. SendChar('B');
  27. }
  28. }
  29. }
  30. void initSys(){
  31. TMOD = 0x21;
  32. SCON = 0x50;
  33. TH0 = T0_H;
  34. TL0 = T0_L;
  35. TH1 = T1_H;
  36. TL1 = T1_L;
  37. EA = 1;
  38. ET0 = 1;
  39. ES = 1;
  40. TR0 = 1;
  41. TR1 = 1;
  42. }
  43. void Timer0Isr() interrupt 1{
  44. static uint8_t counts = 0;
  45. TH0 = T0_H;
  46. TL0 = T0_L;
  47. if(counts++>=20){
  48. counts = 0;
  49. b1sFlag =1;
  50. }
  51. }
  52. void uartIsr()interrupt 4{
  53. uint8_t recvData;
  54. if(RI){
  55. RI = 0 ;
  56. recvData = SBUF;
  57. if(recvData == 'A'){
  58. bRecvFlag = 1;
  59. }
  60. }
  61. }
  62. //串口查询方式发送1个字节数据
  63. void SendChar(uint8_t u8Data){
  64. SBUF = u8Data; //启动发送(注意串口是低速设备,只是启动发送并没有发送完成!)
  65. while(!TI);//等待发送完成
  66. TI = 0;//只要执行到此处,说明发送完成了(TI为1),将TI清零以免下次无法发送。
  67. }

image_1cnmbjv611942pq493q96k6sf13.png-25kB
image_1cnmbikmcsm013r1bjcut21og6m.png-39kB

2.3.4 串口通信协议设计

2.3.4.1 MCS-51串口及其驱动程序设计要点及其存在的问题

2.3.4.2 通信协议的成帧机制

帧头 地址 命令码 数据域 校验和 帧尾
head addr cmd data0-datan checksum end
'@' '0''1' 'D' '1''2''3''4' '1''0' '\r''\n'
40H 30H31H 44H 31H32H33H34H 31H30H 0D0A

"@01D123410\r\n"

2.3.4.2 串口通信协议示例

  1. #include <reg51.h>
  2. #include <stdlib.h>
  3. #include <stdio.h>
  4. #include <intrins.h>
  5. #include "common.h"
  6. #define FOSC 11059200ul
  7. #define BAUD 9600
  8. #define T1_H (256-FOSC/12/32/BAUD)
  9. #define T0_H (65536-(50*FOSC)/(12*1000))/256
  10. #define T0_L (65536-(50*FOSC)/(12*1000))%256
  11. uint16_t sendData = 3124;
  12. uint8_t u8SendData1[]="@01D000000\r\n";
  13. uint8_t recvBuf[32] = {0};
  14. uint8_t recvIndex = 0;
  15. void initSys();
  16. void SendChar(uint8_t u8Data);
  17. bit b1sFlag = 0;
  18. bit bRecvFlag = 0;
  19. sbit TLC549_CS = P1^1;
  20. sbit TLC549_DOUT = P1^0;
  21. sbit TLC549_CLK = P1^2;
  22. uint8_t bdata AdValue;
  23. sbit AIN = AdValue^0;
  24. uint8_t getAdValue(){
  25. uint8_t i;
  26. TLC549_CS = 0;
  27. TLC549_DOUT = 1;
  28. TLC549_CLK = 0;
  29. for(i=0;i<8;i++){
  30. TLC549_CLK = 1;
  31. _nop_();
  32. _nop_();
  33. AdValue = AdValue<<1;
  34. AIN = TLC549_DOUT;
  35. TLC549_CLK = 0;
  36. _nop_();
  37. _nop_();
  38. }
  39. TLC549_CS = 1;
  40. return AdValue;
  41. }
  42. void main(){
  43. uint8_t i;
  44. int8_t i8Buf[5];
  45. initSys();
  46. while(1){
  47. if(b1sFlag){
  48. b1sFlag = 0;
  49. sendData = (uint16_t)((5.0/255.0) * (float)getAdValue()*1000);
  50. }
  51. if(bRecvFlag){
  52. bRecvFlag = 0;
  53. sprintf(i8Buf,"%04x",sendData);
  54. u8SendData1[4] = i8Buf[0];
  55. u8SendData1[5] = i8Buf[1];
  56. u8SendData1[6] = i8Buf[2];
  57. u8SendData1[7] = i8Buf[3];
  58. for(i=0; i<(sizeof(u8SendData1)-1);i++){
  59. SendChar(u8SendData1[i]);
  60. }
  61. }
  62. }
  63. }
  64. void initSys(){
  65. TMOD = 0x21;
  66. TH0 = T0_H;
  67. TL0 = T0_L;
  68. TH1 = T1_H;
  69. TL1 = T1_H;
  70. SCON = 0x50;
  71. EA = 1;
  72. ET0 = 1;
  73. ES = 1;
  74. TR0 = 1;
  75. TR1 = 1;
  76. }
  77. void timer0Isr() interrupt 1{
  78. static uint8_t counts = 0;
  79. TH0 = T0_H;
  80. TL0 = T0_L;
  81. if(counts++ >= 20){
  82. counts =0;
  83. b1sFlag = 1;
  84. }
  85. }
  86. void serialIsr()interrupt 4{
  87. uint8_t recvData;
  88. if(RI){
  89. RI = 0;
  90. recvData = SBUF;
  91. if(recvData == '@'){
  92. recvIndex = 0;
  93. }
  94. if(recvIndex <31){
  95. recvBuf[recvIndex++] = recvData;
  96. }
  97. else{
  98. recvIndex = 0;
  99. }
  100. if(recvData == '\n'){
  101. bRecvFlag = 1;
  102. }
  103. }
  104. }
  105. //串口查询方式发送1个字节数据
  106. void SendChar(uint8_t u8Data){
  107. SBUF = u8Data; //启动发送(注意串口是低速设备,只是启动发送并没有发送完成!)
  108. while(!TI);//等待发送完成
  109. TI = 0; //只要执行到此处,说明发送完成了(TI为1),将TI清零以免下次无法发送。
  110. }

image_1cnob9ina1u7g7qbe5ns9u1b1u9.png-34.1kB
image_1cnobe38rt1r6jm1gleggb16282m.png-10.3kBimage_1cnobi0c5mmj1e9c1u2hkhd1od633.png-35.1kB

2.3.4.3 课堂作业

image.png-87.5kB
image.png-61.4kB

  1. #include "reg51.h"
  2. #include <intrins.h>
  3. #include <stdlib.h>
  4. #include <stdio.h>
  5. #include "common.h"
  6. #define FOSC 11059200ul
  7. #define BAUD 9600
  8. #define T1_H (256-FOSC/12/32/BAUD)
  9. #define T0_H (65536-(2*FOSC)/(1000*12))/256
  10. #define T0_L (65536-(2*FOSC)/(1000*12))%256
  11. sbit COM0 = P1^0;
  12. sbit COM1 = P1^1;
  13. sbit COM2 = P1^2;
  14. sbit COM3 = P1^3;
  15. sbit DO1 = P3^2;
  16. sbit TLC549_CS = P1^6;
  17. sbit TLC549_DOUT = P1^5;
  18. sbit TLC549_CLK = P1^7;
  19. bit flag = 0;
  20. bit flag1 = 0;
  21. uint8_t ADcounts = 0;
  22. uint8_t dispBuf[] = {2,0,1,8};
  23. uint8_t code ledDeg[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90};
  24. uint8_t bdata AdValue;
  25. sbit AIN = AdValue^0;
  26. uint16_t sendData = 3124;
  27. uint8_t u8SendData1[]="@12D00001111222200\r\n";
  28. uint8_t code u8SendData2[]="$12$\r\n";
  29. uint8_t idata recvBuf[16] = {0};
  30. uint8_t recvIndex = 0;
  31. void initSys();
  32. void SendChar(uint8_t u8Data);
  33. bit bRecvFlag = 0;
  34. uint8_t getAdValue(){
  35. uint8_t i;
  36. TLC549_CS = 0;
  37. TLC549_DOUT = 1;
  38. TLC549_CLK = 0;
  39. for(i=0;i<8;i++){
  40. AdValue = AdValue<<1;
  41. TLC549_CLK = 1;
  42. _nop_();
  43. _nop_();
  44. AIN = TLC549_DOUT;
  45. TLC549_CLK = 0;
  46. _nop_();
  47. _nop_();
  48. }
  49. TLC549_CS = 1;
  50. return AdValue;
  51. }
  52. void main(){
  53. uint8_t i = 0;
  54. uint8_t j = 0;
  55. uint8_t ucAdValue=0;
  56. uint16_t uiAdValue =0;
  57. float fAdValue = 0.0;
  58. int8_t i8Buf[5];
  59. initSys();
  60. while(1){
  61. if(flag1){
  62. flag1 = 0;
  63. ucAdValue = getAdValue();
  64. fAdValue = (float)(ucAdValue*(5.0/255.0));
  65. uiAdValue= fAdValue * 1000;
  66. sendData = uiAdValue;
  67. for(j=0;j<4;j++){
  68. dispBuf[3-j]= uiAdValue%10;
  69. uiAdValue /=10;
  70. }
  71. }
  72. if(flag)
  73. {
  74. flag = 0;
  75. P2 = 0xff;
  76. switch(i){
  77. case 0:
  78. COM0=1;COM1=0;COM2=0;COM3=0;
  79. break;
  80. case 1:
  81. COM0=0;COM1=1;COM2=0;COM3=0;
  82. break;
  83. case 2:
  84. COM0=0;COM1=0;COM2=1;COM3=0;
  85. break;
  86. case 3:
  87. COM0=0;COM1=0;COM2=0;COM3=1;
  88. break;
  89. }
  90. P2 = ledDeg[dispBuf[i]];
  91. if(i==0)
  92. P2 &= 0x7f;
  93. if(++i>=4){
  94. i=0;
  95. }
  96. }
  97. if(bRecvFlag){
  98. bRecvFlag = 0;
  99. if(recvBuf[0] == '$'){
  100. for(i=0; i<(sizeof(u8SendData2)-1);i++){
  101. SendChar(u8SendData2[i]);
  102. }
  103. }
  104. if(recvBuf[0] == '@'){
  105. if(recvBuf[3] == 'd'){
  106. sprintf(i8Buf,"%04x",sendData);
  107. u8SendData1[4] = i8Buf[0];
  108. u8SendData1[5] = i8Buf[1];
  109. u8SendData1[6] = i8Buf[2];
  110. u8SendData1[7] = i8Buf[3];
  111. u8SendData1[8] = i8Buf[0];
  112. u8SendData1[9] = i8Buf[1];
  113. u8SendData1[10] = i8Buf[2];
  114. u8SendData1[11] = i8Buf[3];
  115. u8SendData1[12] = i8Buf[0];
  116. u8SendData1[13] = i8Buf[1];
  117. u8SendData1[14] = i8Buf[2];
  118. u8SendData1[15] = i8Buf[3];
  119. for(i=0; i<(sizeof(u8SendData1)-1);i++){
  120. SendChar(u8SendData1[i]);
  121. }
  122. }
  123. if(recvBuf[3] == 'f'){
  124. if(recvBuf[7] == '1'){
  125. DO1 = 0;
  126. }
  127. if(recvBuf[7] == '0'){
  128. DO1 = 1;
  129. }
  130. }
  131. }
  132. }
  133. }
  134. }
  135. void initSys(){
  136. TMOD = 0x21;
  137. TH0 = T0_H;
  138. TL0 = T0_L;
  139. TH1 = T1_H;
  140. TL1 = T1_H;
  141. EA = 1;
  142. ET0 =1;
  143. SCON = 0x50;
  144. EA = 1;
  145. ET0 = 1;
  146. ES = 1;
  147. TR0 = 1;
  148. TR1 = 1;
  149. }
  150. void timer0ISR()interrupt 1{
  151. TH0 = T0_H;
  152. TL0 = T0_L;
  153. flag = 1;
  154. if(ADcounts++>=40){
  155. ADcounts = 0;
  156. flag1 = 1;
  157. }
  158. }
  159. void serialIsr()interrupt 4{
  160. uint8_t recvData;
  161. if(RI){
  162. RI = 0;
  163. recvData = SBUF;
  164. if(recvData == '@' || recvData == '$'){
  165. recvIndex = 0;
  166. }
  167. if(recvIndex <31){
  168. recvBuf[recvIndex++] = recvData;
  169. }
  170. else{
  171. recvIndex = 0;
  172. }
  173. if(recvData == '\n'){
  174. bRecvFlag = 1;
  175. }
  176. }
  177. }
  178. void SendChar(uint8_t u8Data){
  179. SBUF = u8Data;
  180. while(!TI);
  181. TI = 0;
  182. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注