共3条
1/1 1 跳转至页
请教斑竹:模拟串口丢包的问题
问
请问斑竹:再用你们用T0模拟串口的C程序的时候,再接收数据包的时候,会有丢包的情况,一帧7字节,接收时,会丢2个包,然后接收正确一次,又会丢2帧,有规律,丢两包,收一包,请问这可能是什么原因造成的啊??
#include "Stc_Simulate_Rs232.h"
sfr16 DPTR = 0x82;
INT8U bdata rs_BUF; //串行收、发时用的移位暂存器。
sbit rs_BUF_bit7 = rs_BUF^7; //移位暂存器的最高位。
INT8U bdata rsFlags;
sbit rs_f_TI=rsFlags^0; //0:正在发送; 1: 一个字符完毕
sbit rs_f_RI_enable= rsFlags^1; //0:禁止接收; 1:允许接收
sbit rs_f_TI_enable = rsFlags^2; //0:禁止发送; 1:允许发送
#ifdef TIMER_0
void timer0 (void) interrupt 1
{
if (rs_RXD == 0 | rs_shift_count > 0)
{
soft_rs232_interrupt();
}
else
{
rs_timerH = rs_TEST_H;
rs_timerL = rs_TEST_L;
}
}
#endif
/****************************************************/
void soft_rs232_init (void) //串口初始化
{
TCON_ENABLE_TIMER = 0; //停止定时器
rs_RXD = 1; //接收脚置成高电平
rs_TXD = 1; //发射脚置成高电平
IE_ETx = 1; //允许定时器中断
EX0 = 1; //允许外部中断0中断
}
void soft_receive_init() //监测起始位
{
TCON_ENABLE_TIMER = 0; //停止定时器
rs_timerH = rs_TEST_H;
rs_timerL = rs_TEST_L;
rs_shift_count = 0;
TCON_ENABLE_TIMER = 1; //启动定时器
}
void soft_receive_begin() //接收开始
{
gbv_RxdEnable = 1;
rs_f_RI_enable = 1; //允许接收
rs_f_TI_enable = 0; //禁止发送
soft_receive_init(); //监测起始位, RXD 下降沿触发接收字节过程.
IE_ETx = 1; //允许定时器中断
}
void soft_receive_disable() //禁止接收
{
EX0 = 0; //INT0中断禁止
IE_ETx = 0; //禁止定时器中断
TCON_ENABLE_TIMER = 0; //停止定时器
rs_RXD = 0; //通知对方单片机 不能发送
gbv_RxdEnable = 0;
rs_f_RI_enable = 0; //禁止接收
rs_f_TI_enable = 1; //允许发送
}
void soft_receive_enable() // 允许接收中断
{
IE_ETx = 0; //禁止定时器中断
TCON_ENABLE_TIMER = 0; //停止定时器
rs_f_TI_enable = 0; //禁止发送
gbv_RxdEnable = 1;
rs_f_RI_enable = 1; //允许接收
rs_RXD = 1; //通知通信对方单片机可以发送
EX0 = 1;//INT0中断允许(放在最后以免函数中被中断)
}
void soft_send_enable (void) //允许发送
{
EX0 = 0; //发送时INT0中断禁止
TCON_ENABLE_TIMER = 0; //停止定时器
rs_RXD = 0; //通知通信对方单片机 不能发送
gbv_RxdEnable = 0;
rs_f_TI_enable = 1; //允许发送
rs_f_RI_enable = 0; //禁止接收
rs_shift_count = 0; //清移位计数器
rs_f_TI = 1; //发送一个字符完毕标志
IE_ETx = 1; //允许定时器中断
TCON_ENABLE_TIMER = 1; //启动定时器
}
void soft_rs232_interrupt( void )
{
INT8U i=3;
static INT8U sucv_BootCount = 0;
/************************ 接收 ****************************/
if (rs_f_RI_enable == 1)
{
if (rs_shift_count == 0) //移位计数器==0, 表示检测到起始位的起点
{
if ( rs_RXD == 1 )
{
sucv_BootCount++;
if(sucv_BootCount < 6)//6次仍无启始位说明是干扰
{
soft_receive_begin(); //起始位错, 从新开始
}
else
{
sucv_BootCount = 0;
TCON_ENABLE_TIMER = 0; //停止定时器
soft_receive_enable();
}
}
else
{
//下次中断在数据位或停止位中的某时刻发生
rs_timerL += rs_FULL_BIT_L + 0x10;
rs_timerH = rs_FULL_BIT_H;
rs_shift_count++;
rs_BUF = 0; //清移位缓冲变量
}
}
else
{
rs_timerL += rs_FULL_BIT_L; //下次中断在数据位或停止位中发生
rs_timerH = rs_FULL_BIT_H;
rs_shift_count++; //2--9:数据位
if ( rs_shift_count == 9)
{
rs_BUF = rs_BUF >> 1; //接收第8位
rs_BUF_bit7 = rs_RXD;
/**********************************/
/**********************************/
//收到停止位,继续检测 PC 机发出的下一个起始位
if( ReceivePoint < rs_RECEIVE_MAX)
{
if(1 == RecCheck(&ReceivePoint, guca_RxdPack)) //接收检查 {
gbv_RxdOKDown = 1;
soft_receive_disable();
}
}
else
{
ReceivePoint = 0;//soft_receive_disable();//缓冲区满, 禁止接收 }
}
else
{
if (rs_shift_count < 9 ) //收到的是数据位 1 -- 7
{
rs_BUF = rs_BUF >> 1;
rs_BUF_bit7 = rs_RXD;
}
else
{
soft_receive_enable(); // 允许接中断
}
}
}
TCON_TFx = 0; //清定时器中断标志
}
else
{
/************************ 发送 ****************************/
if (rs_f_TI_enable == 1)
{
rs_timerL += rs_FULL_BIT_L;//下次中断在数据位的末尾时刻
rs_timerH = rs_FULL_BIT_H;
rs_shift_count--; //0:停止位末尾时刻到
//1:发送停止位
//2--9:发送数据位
if (rs_shift_count > 9) //错误状态
{
rs_shift_count = 9;
rs_BUF = 0xFF;
}
if (rs_shift_count > 1) //2--9:发送数据位
{
ACC = rs_BUF;
ACC = ACC >> 1;
rs_TXD = CY;
rs_BUF = ACC;
}
else
{
if (rs_shift_count == 0) //0:停止位末尾时刻到
{
rs_TXD = 1;
rs_f_TI = 1; //已发送完毕一个字节
}
else
{
rs_TXD = 1; //1:发送停止位
}
}
}
}
}
//由收转到发时,要先调用 soft_send_enable ()
void rs_send_byte(INT8U SendByte) //发送一个字节
{
gbv_SndByteTWait = 1;
gucv_SndByteTCount = 0;
while ( rs_f_TI == 0) //等待发送完毕前一个字节
{
if (!gbv_SndByteTWait) //避免死循环
{
rs_f_TI = 1;
}
}
rs_TXD = 1;
rs_timerL=rs_START_BIT_L;//下次中断在起始位的末尾时刻
rs_timerH = rs_START_BIT_H;
rs_BUF = SendByte;
rs_shift_count = 10;
rs_TXD = 0; //发送起始位
rs_f_TI = 0; //清已发送完毕一个字节的标志
}
//INT0中断服务子程,用于模拟串口接收起始位触发
void Extern0_ISR() interrupt 0
{
EX0 = 0; //INT0中断禁止
soft_receive_begin(); //开始接收
}
INT8U RecCheck(INT8U *lucv_RxdCount, INT8U luca_RxdPack[]) //接收检查
{
INT16U TmpCrc = 0;
putbf(rs_BUF); //打印数据,在串口调试助手中观察到每隔两包收一包
if (!((*lucv_RxdCount) < rs_RECEIVE_MAX))
{
*lucv_RxdCount = 0;
}
switch (*lucv_RxdCount)
{
case 0:
if (HEADCHAR != rs_BUF)//头标志错误则抛弃包
{
(*lucv_RxdCount) = 0;
return 0;
}
break;
case 1:
break;
case 2:
if (rs_BUF > rs_RECEIVE_MAX - 2)//最多接收字节(不包括crc)
{
(*lucv_RxdCount) = 0;
return 0;
}
else
break;
default:
//到指定接收长度.gucv_RxdCount与下标位相同,因此比实际字节数少1
if ((*lucv_RxdCount) >= (luca_RxdPack[2] +2 - 1))//到指定接收长度
{
luca_RxdPack[*lucv_RxdCount] = rs_BUF;
if (TAILCHAR == luca_RxdPack[(*lucv_RxdCount)] ) //结束标志正确?
{
(*lucv_RxdCount) = 0;
if(!(Cal_Crc(&luca_RxdPack[1],luca_RxdPack[2])))
{
return 1;
}
}
(*lucv_RxdCount) = 0;
return 0;
}
}
luca_RxdPack[*lucv_RxdCount] = rs_BUF;
(*lucv_RxdCount)++;
return 2;
}
void SendSimula(const INT8U luca_Dataes[])
{
INT8U n = 0;
INT8U lucv_Leng = 0;
INT8U xdata luca_Pack[rs_SEND_MAX];
lucv_Leng = luca_Dataes[1] + 4;
Pack_Dataes(luca_Pack, luca_Dataes);
for (n = 0; n < lucv_Leng; n++)
{
rs_send_byte(luca_Pack[n]);
}
gbv_SndByteTWait = 1;
gucv_SndByteTCount = 0;
while( rs_f_TI == 0) //等待发送完毕前一个字节
{
if (!gbv_SndByteTWait) //避免死循环
{
rs_f_TI = 1;
}
} // 等待最后一个字节发送完毕
}
答 1: 肯定你软件的原因喽 答 2: OK解决了,自己的失误 答 3: 恭喜,我们只是写个样例程序,供大家参考,帮大家省些宝贵时间恭喜,我们只是写个样例程序,供大家参考,帮大家省些宝贵时间
#include "Stc_Simulate_Rs232.h"
sfr16 DPTR = 0x82;
INT8U bdata rs_BUF; //串行收、发时用的移位暂存器。
sbit rs_BUF_bit7 = rs_BUF^7; //移位暂存器的最高位。
INT8U bdata rsFlags;
sbit rs_f_TI=rsFlags^0; //0:正在发送; 1: 一个字符完毕
sbit rs_f_RI_enable= rsFlags^1; //0:禁止接收; 1:允许接收
sbit rs_f_TI_enable = rsFlags^2; //0:禁止发送; 1:允许发送
#ifdef TIMER_0
void timer0 (void) interrupt 1
{
if (rs_RXD == 0 | rs_shift_count > 0)
{
soft_rs232_interrupt();
}
else
{
rs_timerH = rs_TEST_H;
rs_timerL = rs_TEST_L;
}
}
#endif
/****************************************************/
void soft_rs232_init (void) //串口初始化
{
TCON_ENABLE_TIMER = 0; //停止定时器
rs_RXD = 1; //接收脚置成高电平
rs_TXD = 1; //发射脚置成高电平
IE_ETx = 1; //允许定时器中断
EX0 = 1; //允许外部中断0中断
}
void soft_receive_init() //监测起始位
{
TCON_ENABLE_TIMER = 0; //停止定时器
rs_timerH = rs_TEST_H;
rs_timerL = rs_TEST_L;
rs_shift_count = 0;
TCON_ENABLE_TIMER = 1; //启动定时器
}
void soft_receive_begin() //接收开始
{
gbv_RxdEnable = 1;
rs_f_RI_enable = 1; //允许接收
rs_f_TI_enable = 0; //禁止发送
soft_receive_init(); //监测起始位, RXD 下降沿触发接收字节过程.
IE_ETx = 1; //允许定时器中断
}
void soft_receive_disable() //禁止接收
{
EX0 = 0; //INT0中断禁止
IE_ETx = 0; //禁止定时器中断
TCON_ENABLE_TIMER = 0; //停止定时器
rs_RXD = 0; //通知对方单片机 不能发送
gbv_RxdEnable = 0;
rs_f_RI_enable = 0; //禁止接收
rs_f_TI_enable = 1; //允许发送
}
void soft_receive_enable() // 允许接收中断
{
IE_ETx = 0; //禁止定时器中断
TCON_ENABLE_TIMER = 0; //停止定时器
rs_f_TI_enable = 0; //禁止发送
gbv_RxdEnable = 1;
rs_f_RI_enable = 1; //允许接收
rs_RXD = 1; //通知通信对方单片机可以发送
EX0 = 1;//INT0中断允许(放在最后以免函数中被中断)
}
void soft_send_enable (void) //允许发送
{
EX0 = 0; //发送时INT0中断禁止
TCON_ENABLE_TIMER = 0; //停止定时器
rs_RXD = 0; //通知通信对方单片机 不能发送
gbv_RxdEnable = 0;
rs_f_TI_enable = 1; //允许发送
rs_f_RI_enable = 0; //禁止接收
rs_shift_count = 0; //清移位计数器
rs_f_TI = 1; //发送一个字符完毕标志
IE_ETx = 1; //允许定时器中断
TCON_ENABLE_TIMER = 1; //启动定时器
}
void soft_rs232_interrupt( void )
{
INT8U i=3;
static INT8U sucv_BootCount = 0;
/************************ 接收 ****************************/
if (rs_f_RI_enable == 1)
{
if (rs_shift_count == 0) //移位计数器==0, 表示检测到起始位的起点
{
if ( rs_RXD == 1 )
{
sucv_BootCount++;
if(sucv_BootCount < 6)//6次仍无启始位说明是干扰
{
soft_receive_begin(); //起始位错, 从新开始
}
else
{
sucv_BootCount = 0;
TCON_ENABLE_TIMER = 0; //停止定时器
soft_receive_enable();
}
}
else
{
//下次中断在数据位或停止位中的某时刻发生
rs_timerL += rs_FULL_BIT_L + 0x10;
rs_timerH = rs_FULL_BIT_H;
rs_shift_count++;
rs_BUF = 0; //清移位缓冲变量
}
}
else
{
rs_timerL += rs_FULL_BIT_L; //下次中断在数据位或停止位中发生
rs_timerH = rs_FULL_BIT_H;
rs_shift_count++; //2--9:数据位
if ( rs_shift_count == 9)
{
rs_BUF = rs_BUF >> 1; //接收第8位
rs_BUF_bit7 = rs_RXD;
/**********************************/
/**********************************/
//收到停止位,继续检测 PC 机发出的下一个起始位
if( ReceivePoint < rs_RECEIVE_MAX)
{
if(1 == RecCheck(&ReceivePoint, guca_RxdPack)) //接收检查 {
gbv_RxdOKDown = 1;
soft_receive_disable();
}
}
else
{
ReceivePoint = 0;//soft_receive_disable();//缓冲区满, 禁止接收 }
}
else
{
if (rs_shift_count < 9 ) //收到的是数据位 1 -- 7
{
rs_BUF = rs_BUF >> 1;
rs_BUF_bit7 = rs_RXD;
}
else
{
soft_receive_enable(); // 允许接中断
}
}
}
TCON_TFx = 0; //清定时器中断标志
}
else
{
/************************ 发送 ****************************/
if (rs_f_TI_enable == 1)
{
rs_timerL += rs_FULL_BIT_L;//下次中断在数据位的末尾时刻
rs_timerH = rs_FULL_BIT_H;
rs_shift_count--; //0:停止位末尾时刻到
//1:发送停止位
//2--9:发送数据位
if (rs_shift_count > 9) //错误状态
{
rs_shift_count = 9;
rs_BUF = 0xFF;
}
if (rs_shift_count > 1) //2--9:发送数据位
{
ACC = rs_BUF;
ACC = ACC >> 1;
rs_TXD = CY;
rs_BUF = ACC;
}
else
{
if (rs_shift_count == 0) //0:停止位末尾时刻到
{
rs_TXD = 1;
rs_f_TI = 1; //已发送完毕一个字节
}
else
{
rs_TXD = 1; //1:发送停止位
}
}
}
}
}
//由收转到发时,要先调用 soft_send_enable ()
void rs_send_byte(INT8U SendByte) //发送一个字节
{
gbv_SndByteTWait = 1;
gucv_SndByteTCount = 0;
while ( rs_f_TI == 0) //等待发送完毕前一个字节
{
if (!gbv_SndByteTWait) //避免死循环
{
rs_f_TI = 1;
}
}
rs_TXD = 1;
rs_timerL=rs_START_BIT_L;//下次中断在起始位的末尾时刻
rs_timerH = rs_START_BIT_H;
rs_BUF = SendByte;
rs_shift_count = 10;
rs_TXD = 0; //发送起始位
rs_f_TI = 0; //清已发送完毕一个字节的标志
}
//INT0中断服务子程,用于模拟串口接收起始位触发
void Extern0_ISR() interrupt 0
{
EX0 = 0; //INT0中断禁止
soft_receive_begin(); //开始接收
}
INT8U RecCheck(INT8U *lucv_RxdCount, INT8U luca_RxdPack[]) //接收检查
{
INT16U TmpCrc = 0;
putbf(rs_BUF); //打印数据,在串口调试助手中观察到每隔两包收一包
if (!((*lucv_RxdCount) < rs_RECEIVE_MAX))
{
*lucv_RxdCount = 0;
}
switch (*lucv_RxdCount)
{
case 0:
if (HEADCHAR != rs_BUF)//头标志错误则抛弃包
{
(*lucv_RxdCount) = 0;
return 0;
}
break;
case 1:
break;
case 2:
if (rs_BUF > rs_RECEIVE_MAX - 2)//最多接收字节(不包括crc)
{
(*lucv_RxdCount) = 0;
return 0;
}
else
break;
default:
//到指定接收长度.gucv_RxdCount与下标位相同,因此比实际字节数少1
if ((*lucv_RxdCount) >= (luca_RxdPack[2] +2 - 1))//到指定接收长度
{
luca_RxdPack[*lucv_RxdCount] = rs_BUF;
if (TAILCHAR == luca_RxdPack[(*lucv_RxdCount)] ) //结束标志正确?
{
(*lucv_RxdCount) = 0;
if(!(Cal_Crc(&luca_RxdPack[1],luca_RxdPack[2])))
{
return 1;
}
}
(*lucv_RxdCount) = 0;
return 0;
}
}
luca_RxdPack[*lucv_RxdCount] = rs_BUF;
(*lucv_RxdCount)++;
return 2;
}
void SendSimula(const INT8U luca_Dataes[])
{
INT8U n = 0;
INT8U lucv_Leng = 0;
INT8U xdata luca_Pack[rs_SEND_MAX];
lucv_Leng = luca_Dataes[1] + 4;
Pack_Dataes(luca_Pack, luca_Dataes);
for (n = 0; n < lucv_Leng; n++)
{
rs_send_byte(luca_Pack[n]);
}
gbv_SndByteTWait = 1;
gucv_SndByteTCount = 0;
while( rs_f_TI == 0) //等待发送完毕前一个字节
{
if (!gbv_SndByteTWait) //避免死循环
{
rs_f_TI = 1;
}
} // 等待最后一个字节发送完毕
}
答 1: 肯定你软件的原因喽 答 2: OK解决了,自己的失误 答 3: 恭喜,我们只是写个样例程序,供大家参考,帮大家省些宝贵时间恭喜,我们只是写个样例程序,供大家参考,帮大家省些宝贵时间
共3条
1/1 1 跳转至页
回复
有奖活动 | |
---|---|
【有奖活动——B站互动赢积分】活动开启啦! | |
【有奖活动】分享技术经验,兑换京东卡 | |
话不多说,快进群! | |
请大声喊出:我要开发板! | |
【有奖活动】EEPW网站征稿正在进行时,欢迎踊跃投稿啦 | |
奖!发布技术笔记,技术评测贴换取您心仪的礼品 | |
打赏了!打赏了!打赏了! |