从单片机基础到程序框架(全集 2019pdf版).pdf - 第795页
//Gu32Rece Cnt_B=0;/ /这里不能清零缓存 B 的计数器,意味 深长,避 免此处临界点 发生中断 Gu8FinishF lag=0; //尽可 能以最快的速 度清零本次完 成的标志,为 下一次 新数据做准备 pSu8ReceBu ffer=(uns igned char * )&Gu8Rece Buffer_A[0]; / /关联刚刚接 收的数据缓存 Su32ReceSi ze=Gu32Re ceCnt_A; …

Gu8ReceBuffer_B[Gu32ReceCnt_B]=SBUF;
Gu32ReceCnt_B++; //记录当前缓存 B 的接收字节数
}
}
}
else //发送数据引起的中断
{
TI = 0; //及时清除发送中断的标志,避免一直无缘无故的进入中断。
//以下可以添加一个全局变量的标志位的相关代码,通知主函数已经发送完一个字节的数据了。
}
}
void UsartTask(void) //串口接收的任务函数,放在主函数内
{
static unsigned char *pSu8ReceBuffer; //“指针切换关联”中的指针,切换内存
static unsigned char Su8Lock=0; //用来避免一直更新的临时变量
static unsigned long i; //用在数据处理中的循环变量
static unsigned long Su32ReceSize=0; //接收到的数据大小的临时变量
if(1==Gu8ReceFeedDog) //每被“喂一次狗”,就及时更新一次“超时检测的定时器”的初值
{
Gu8ReceFeedDog=0;
Su8Lock=0; //解锁。用来避免一直更新的临时变量
//以下三行代码是看门狗中的“喂狗”操作。继续给软件定时器“输血”
vGu8ReceTimeOutFlag=0;
vGu16ReceTimeOutCnt=DOG_TIME_OUT;//正在通信时,两个字节间隔的最大时间,本节选用 20ms
vGu8ReceTimeOutFlag=1;
}
else if(0==Su8Lock&&0==vGu16ReceTimeOutCnt) //超时,代表一串数据已经接收完成
{
Su8Lock=1; //避免一直进来更新
Gu8FinishFlag=1; //两个字节之间的时间超时,因此代表了一串数据已经接收完成
}
if(1==Gu8FinishFlag) //1 代表已经接收完毕一串新的数据,需要马上去处理
{
if(0==Gu8CurrentReceBuffer_Sec)
{
Gu8CurrentReceBuffer_Sec=1; //以最快的速度先切换接收内存,避免丢失新发过来的数据

//Gu32ReceCnt_B=0;//这里不能清零缓存 B 的计数器,意味深长,避免此处临界点发生中断
Gu8FinishFlag=0; //尽可能以最快的速度清零本次完成的标志,为下一次新数据做准备
pSu8ReceBuffer=(unsigned char *)&Gu8ReceBuffer_A[0]; //关联刚刚接收的数据缓存
Su32ReceSize=Gu32ReceCnt_A; //记录当前缓存的有效字节数
Gu32ReceCnt_A=0; //及时把当前缓存计数清零,为一次切换接收缓存做准备。意味深长。
}
else
{
Gu8CurrentReceBuffer_Sec=0; //以最快的速度先切换接收内存,避免丢失新发过来的数据
//Gu32ReceCnt_A=0;//这里不能清零缓存 A 的计数器,意味深长,避免此处临界点发生中断
Gu8FinishFlag=0; //尽可能以最快的速度清零本次完成的标志,为下一次新数据做准备
pSu8ReceBuffer=(unsigned char *)&Gu8ReceBuffer_B[0]; //关联刚刚接收的数据缓存
Su32ReceSize=Gu32ReceCnt_B; //记录当前缓存的有效字节数
Gu32ReceCnt_B=0; //及时把当前缓存计数清零,为一次切换接收缓存做准备。意味深长。
}
//Gu8FinishFlag=0; //之所以不选择在这里清零,是因为在上面清零更及时快速。意味深长。
//开始处理刚刚接收到的一串新数据,直接“统一”处理 pSu8ReceBuffer 指针为代表的数据即可
for(i=0;i<Su32ReceSize;i++)
{
if(0x02==pSu8ReceBuffer[i]&&
0x03==pSu8ReceBuffer[i+1]&&
0x04==pSu8ReceBuffer[i+2]) //连续三个数是 0x02 0x03 0x04
{
vGu8BeepTimerFlag=0;
vGu16BeepTimerCnt=100; //让蜂鸣器“短叫”100ms
vGu8BeepTimerFlag=1;
return; //直接退出当前函数
}
if(0x06==pSu8ReceBuffer[i]&&
0x07==pSu8ReceBuffer[i+1]&&
0x08==pSu8ReceBuffer[i+2]&&
0x09==pSu8ReceBuffer[i+3]) //连续四个数是 0x06 0x07 0x08 0x09
{
vGu8BeepTimerFlag=0;
vGu16BeepTimerCnt=2000; //让蜂鸣器“长叫”2000ms
vGu8BeepTimerFlag=1;
return; //直接退出当前函数
}
}

}
}
void T0_time() interrupt 1
{
VoiceScan();
if(1==vGu8ReceTimeOutFlag&&vGu16ReceTimeOutCnt>0) //通信过程中字节之间的超时定时器
{
vGu16ReceTimeOutCnt--;
}
TH0=0xfc;
TL0=0x66;
}
void SystemInitial(void)
{
unsigned char u8_TMOD_Temp=0;
//以下是定时器 0 的中断的配置
TMOD=0x01;
TH0=0xfc;
TL0=0x66;
EA=1;
ET0=1;
TR0=1;
//以下是串口接收中断的配置
//串口的波特率与内置的定时器 1 直接相关,因此配置此定时器 1 就等效于配置波特率。
u8_TMOD_Temp=0x20; //即将把定时器 1 设置为:工作方式 2,初值自动重装的 8 位定时器。
TMOD=TMOD&0x0f; //此寄存器低 4 位是跟定时器 0 相关,高 4 位是跟定时器 1 相关。先清零定时器 1。
TMOD=TMOD|u8_TMOD_Temp; //把高 4 位的定时器 1 填入 0x2,低 4 位的定时器 0 保持不变。
TH1=256-(11059200L/12/32/9600); //波特率为 9600。11059200 代表晶振 11.0592MHz,
TL1=256-(11059200L/12/32/9600); //L 代表 long 的长类型数据。根据芯片手册提供的计算公式。
TR1=1; //开启定时器 1
SM0=0;
SM1=1; //SM0 与 SM1 的设置:选择 10 位异步通信,波特率根据定时器 1 可变
REN=1; //允许串口接收数据
//为了保证串口中断接收的数据不丢失,必须设置 IP = 0x10,相当于把串口中断设置为最高优先级,
//这个时候,串口中断可以打断任何其他的中断服务函数实现嵌套,