请教串口接收数据被别的事件长时间打断后再接收数据错...
在STC15串口3接了一个测距模块,模块是上电后就发送数据的,现在碰到一个问题,正常上电后收到的模块数据是对的(把串口3收到的数据同时转发到串口1,用串口助手监控),如果按了外接的一个按键,进行别的操作,中间差不多延时20秒的时间,等操作结束发现数据错位了,比如正常的十几个字节是00 11 22 33 44 55 66 77 88 99 AA BB这样的,进行按键操作结束串口收到的数据就变成 BB 00 11 22 33 44 55 66 77 88 99 AA这样的了,不知道有的兄弟4个串口同时使用的时候是怎么分别处理不会影响的?/********************** 主程序**************************/
void main()
{
P0n_standard(0xff); //设置为准双向口
P1n_standard(0xff); //设置为准双向口
P2n_standard(0xff); //设置为准双向口
P3n_standard(0xff); //设置为准双向口
P4n_standard(0xff); //设置为准双向口
P5n_standard(0xff); //设置为准双向口
P6n_standard(0xff); //设置为准双向口
P7n_standard(0xff); //设置为准双向口
UART1_config(2); // 选择波特率, 2: 使用Timer2做波特率, 其它值: 使用Timer1做波特率.
UART2_config(2); // 选择波特率, 2: 使用Timer2做波特率, 其它值: 无效.
UART3_config(2); // 选择波特率, 2: 使用Timer2做波特率, 其它值: 使用Timer3做波特率.
UART4_config(2); // 选择波特率, 2: 使用Timer2做波特率, 其它值: 使用Timer4做波特率.
EA = 1;
RunLED = 0; //开机运行灯亮
LED = 1; //状态灯灭
while(1)
{
KeyScan(); //按键扫描
UART3_Proc(); //串口3测距处理
}
}
/********************** 1ms延时程序**************************/
void Delay1ms(unsigned int mDelay1) //1ms延时,22.1184M晶振
{
unsigned int mDelay2;
for(;mDelay1>0;mDelay1--)
{
for(mDelay2=0;mDelay2<2000;mDelay2++)
{;;}
}
}
/********************** 开门/关门按键检测**************************/
void KeyScan()
{
if(OpenKey == 0) //有开门按键
{
Delay1ms(20);
if(OpenKey == 0)
{
MotorFI = 1; //电机正转开门
MotorBI = 0;
Delay1ms(20000); //等20秒
MotorFI = 0; //电机反转关门
MotorBI = 1;
}
}
if(CloseKey == 0) //如果检测到关门开关闭合
{
Delay1ms(20);
if(CloseKey == 0)
{
Delay1ms(20000); //等20秒
MotorFI = 1; //关闭电机供电
MotorBI = 1;
}
}
}
//========================================================================
// 函数: SetTimer2Baudraye(u16 dat)
// 描述: 设置Timer2做波特率发生器。
// 参数: dat: Timer2的重装值.
// 返回: none.
// 版本: VER1.0
// 日期: 2014-11-28
// 备注:
//========================================================================
void SetTimer2Baudraye(u16 dat) // 选择波特率, 2: 使用Timer2做波特率, 其它值: 使用Timer1做波特率.
{
AUXR &= ~(1<<4); //Timer stop
AUXR &= ~(1<<3); //Timer2 set As Timer
AUXR |=(1<<2); //Timer2 set as 1T mode
TH2 = dat / 256;
TL2 = dat % 256;
IE2&= ~(1<<2); //禁止中断
AUXR |=(1<<4); //Timer run enable
}
//========================================================================
// 函数: void UART1_config(u8 brt)
// 描述: UART1初始化函数。
// 参数: brt: 选择波特率, 2: 使用Timer2做波特率, 其它值: 使用Timer1做波特率.
// 返回: none.
// 版本: VER1.0
// 日期: 2014-11-28
// 备注:
//========================================================================
void UART1_config(u8 brt) // 选择波特率, 2: 使用Timer2做波特率, 其它值: 使用Timer1做波特率.
{
u8 i;
/*********** 波特率使用定时器2 *****************/
if(brt == 2)
{
AUXR |= 0x01; //S1 BRT Use Timer2;
SetTimer2Baudraye(65536UL - (MAIN_Fosc / 4) / UART_BaudRate1);
}
/*********** 波特率使用定时器1 *****************/
else
{
TR1 = 0;
AUXR &= ~0x01; //S1 BRT Use Timer1;
AUXR |=(1<<6); //Timer1 set as 1T mode
TMOD &= ~(1<<6); //Timer1 set As Timer
TMOD &= ~0x30; //Timer1_16bitAutoReload;
TH1 = (65536UL - (MAIN_Fosc / 4) / UART_BaudRate1) / 256;
TL1 = (65536UL - (MAIN_Fosc / 4) / UART_BaudRate1) % 256;
ET1 = 0; //禁止中断
INT_CLKO &= ~0x02; //不输出时钟
TR1= 1;
}
/*************************************************/
SCON = (SCON & 0x3f) | (1<<6); // 8位数据, 1位起始位, 1位停止位, 无校验
// PS= 1; //高优先级中断
ES= 1; //允许中断
REN = 1; //允许接收
P_SW1 = P_SW1 & 0x3f; //切换到 P3.0 P3.1
// P_SW1 = (P_SW1 & 0x3f) | (1<<6); //切换到P3.6 P3.7
// P_SW1 = (P_SW1 & 0x3f) | (2<<6); //切换到P1.6 P1.7 (必须使用内部时钟)
for(i=0; i<RX1_Length; i++) RX1_Buffer = 0;
B_TX1_Busy= 0;
TX1_read = 0;
RX1_write = 0;
}
//========================================================================
// 函数: void UART2_config(u8 brt)
// 描述: UART2初始化函数。
// 参数: brt: 选择波特率, 2: 使用Timer2做波特率, 其它值: 无效.
// 返回: none.
// 版本: VER1.0
// 日期: 2014-11-28
// 备注:
//========================================================================
void UART2_config(u8 brt) // 选择波特率, 2: 使用Timer2做波特率, 其它值: 无效.
{
u8 i;
/*********** 波特率固定使用定时器2 *****************/
if(brt == 2) SetTimer2Baudraye(65536UL - (MAIN_Fosc / 4) / UART_BaudRate2);
S2CON &= ~(1<<7); // 8位数据, 1位起始位, 1位停止位, 无校验
IE2 |= 1; //允许中断
S2CON |= (1<<4); //允许接收
P_SW2 &= ~1; //切换到 P1.0 P1.1
// P_SW2 |= 1; //切换到 P4.6 P4.7
for(i=0; i<RX2_Length; i++) RX2_Buffer = 0;
B_TX2_Busy= 0;
TX2_read = 0;
RX2_write = 0;
}
//========================================================================
// 函数: void UART3_config(u8 brt)
// 描述: UART3初始化函数。
// 参数: brt: 选择波特率, 2: 使用Timer2做波特率, 其它值: 使用Timer3做波特率.
// 返回: none.
// 版本: VER1.0
// 日期: 2014-11-28
// 备注:
//========================================================================
void UART3_config(u8 brt) // 选择波特率, 2: 使用Timer2做波特率, 其它值: 使用Timer3做波特率.
{
u8 i;
/*********** 波特率固定使用定时器2 *****************/
if(brt == 2)
{
S3CON &= ~(1<<6); //BRT select Timer2
SetTimer2Baudraye(65536UL - (MAIN_Fosc / 4) / UART_BaudRate3);
}
/*********** 波特率使用定时器3 *****************/
else
{
S3CON |= (1<<6); //BRT select Timer3
T4T3M &= 0xf0; //停止计数, 清除控制位
IE2&= ~(1<<5); //禁止中断
T4T3M |=(1<<1); //1T
T4T3M &= ~(1<<2); //定时
T4T3M &= ~1; //不输出时钟
TH3 = (65536UL - (MAIN_Fosc / 4) / UART_BaudRate3) / 256;
TL3 = (65536UL - (MAIN_Fosc / 4) / UART_BaudRate3) % 256;
T4T3M |=(1<<3); //开始运行
}
S3CON &= ~(1<<5); //禁止多机通讯方式
S3CON &= ~(1<<7); // 8位数据, 1位起始位, 1位停止位, 无校验
// IE2 &= ~(1<<3); //串口3禁止中断
IE2 |=(1<<3); //串口3允许中断
S3CON |=(1<<4); //串口3允许接收
P_SW2 &= ~2; //切换到 P0.0 P0.1
// P_SW2 |= 2; //切换到 P5.0 P5.1
for(i=0; i<RX3_Length; i++) RX3_Buffer = 0;
B_TX3_Busy= 0;
TX3_read = 0;
RX3_write = 0;
}
//========================================================================
// 函数: void UART4_config(u8 brt)
// 描述: UART4初始化函数。
// 参数: brt: 选择波特率, 2: 使用Timer2做波特率, 其它值: 使用Timer4做波特率.
// 返回: none.
// 版本: VER1.0
// 日期: 2014-11-28
// 备注:
//========================================================================
void UART4_config(u8 brt) // 选择波特率, 2: 使用Timer2做波特率, 其它值: 使用Timer4做波特率.
{
u8 i;
/*********** 波特率固定使用定时器2 *****************/
if(brt == 2)
{
S4CON &= ~(1<<6); //BRT select Timer2
SetTimer2Baudraye(65536UL - (MAIN_Fosc / 4) / UART_BaudRate4);
}
/*********** 波特率使用定时器3 *****************/
else
{
S4CON |= (1<<6); //BRT select Timer4
T4T3M &= 0x0f; //停止计数, 清除控制位
IE2 &= ~(1<<6); //禁止中断
T4T3M |=(1<<5); //1T
T4T3M &= ~(1<<6); //定时
T4T3M &= ~(1<<4); //不输出时钟
TH4 = (65536UL - (MAIN_Fosc / 4) / UART_BaudRate4) / 256;
TL4 = (65536UL - (MAIN_Fosc / 4) / UART_BaudRate4) % 256;
T4T3M |=(1<<7); //开始运行
}
S4CON &= ~(1<<5); //禁止多机通讯方式
S4CON &= ~(1<<7); // 8位数据, 1位起始位, 1位停止位, 无校验
IE2 |=(1<<4); //允许中断
S4CON |=(1<<4); //允许接收
P_SW2 &= ~4; //切换到 P0.2 P0.3
// P_SW2 |= 4; //切换到 P5.2 P5.3
for(i=0; i<RX4_Length; i++) RX4_Buffer = 0;
B_TX4_Busy= 0;
TX4_read = 0;
RX4_write = 0;
}
//========================================================================
//
//
// 串口发送一个字节和字符串
//
//
//========================================================================
void UART1_Send(u8 tx1)
{
B_TX1_Busy = 1; //标志发送忙
SBUF = tx1; //发一个字节
while(B_TX1_Busy); //等待发送完成
}
void UART3_Send(u8 tx3)
{
B_TX3_Busy = 1; //标志发送忙
S3BUF = tx3; //发一个字节
while(B_TX3_Busy); //等待发送完成
}
void PrintString1(u8 *puts)
{
for (; *puts != 0; puts++)
{
B_TX1_Busy = 1; //标志发送忙
SBUF = *puts; //发一个字节
while(B_TX1_Busy); //等待发送完成
}
}
void PrintString3(u8 *puts)
{
for (; *puts != 0; puts++)
{
B_TX3_Busy = 1; //标志发送忙
S3BUF = *puts; //发一个字节
while(B_TX3_Busy); //等待发送完成
}
}
/********************* UART1中断函数************************/
void UART1_int (void) interrupt UART1_VECTOR
{
if(RI)
{
RI = 0;
RX1_Buffer = SBUF;
if(++RX1_write >= RX1_Length) RX1_write = 0;
}
if(TI)
{
TI = 0;
B_TX1_Busy = 0;
}
}
/********************* UART3中断函数************************/
void UART3_int (void) interrupt UART3_VECTOR
{
if(RI3)
{
CLR_RI3();
RX3_Buffer = S3BUF;
RT3 = S3BUF; //读入缓冲区
R3_flag=1; //有数据,建立标志
if(++RX3_write >= RX3_Length) RX3_write = 0;
}
if(TI3)
{
CLR_TI3();
B_TX3_Busy = 0;
}
}
/********************* UART3处理函数************************/
void UART3_Proc()
{
if(!R3_flag)return; //没有新数据,返回
R3_flag=0; //清零数据标志
RX3_Buffer=RT3; //数据存入缓冲区
CT3++; //指针加1指向一下存储单元
if(CT3>=13) //判断指针是否超范围
{
CT3=0;
UART1_Send(RX3_Buffer);//转发到串口1查看是否正确
UART1_Send(RX3_Buffer);
UART1_Send(RX3_Buffer);
UART1_Send(RX3_Buffer);
UART1_Send(RX3_Buffer);
UART1_Send(RX3_Buffer);
UART1_Send(RX3_Buffer);
UART1_Send(RX3_Buffer);
UART1_Send(RX3_Buffer);
UART1_Send(RX3_Buffer);
UART1_Send(RX3_Buffer);
UART1_Send(RX3_Buffer);
UART1_Send(RX3_Buffer);
}
}
缓冲区太小, 循环覆盖了。 模块每次发送数据是固定的,13个字节 没有仔细看程序,如果模块的数据是一直发送的,可以考虑加个数据校验吧,校验不正确的数据就丢弃了 没有看明白楼主,先不看楼主代码,看下楼主人吧,
肯定是设计思路问题,数据是一直有还是随机有,还是不知道啥时候有,你那20秒钟时间内要收多少串口数据{:lol:} 我也好想遇到过,我用的串口1和串口2,串口2连了一块串口屏,不确定什么时候会用数据过来,关键是我还tm用了一个ad,读取ad的时候时序不能被打断,所以只能关掉中断,那么如果我在读ad的时候来了串口数据,我还能收到吗?如果低优先级的串口正在接受数据这时候高级别串口中断来了,那么我低优先级的中断不会被打乱吗?串口中断执行后距离下一个字符过来还有一点点时间,这个时间我的单片机是在执行我的程序吗?如果正好执行到了ad那部分,把中断关了,那么下一帧就接受不到了啊?,,,我最后只用了一个串口。。我也不知道怎么解决 /********************* UART3中断函数************************/
void UART3_int (void) interrupt UART3_VECTOR
{
if(RI3)
{
CLR_RI3();
RX3_Buffer = S3BUF;
RT3 = S3BUF; //读入缓冲区
R3_flag=1; //有数据,建立标志
if(++RX3_write >= RX3_Length) RX3_write = 0; 你这里啥意思,接收个数达到 RX3_Length 后RX3_write=0那么下一个数据来了不就是覆盖吗,难道是这么简单的思路{:lol:}{:biggrin:}{:funk:}{:curse:}
}
if(TI3)
{
CLR_TI3();
B_TX3_Busy = 0;
}
} UVPOWER 发表于 2019-8-29 17:23
没有仔细看程序,如果模块的数据是一直发送的,可以考虑加个数据校验吧,校验不正确的数据就丢弃了 ...
模块数据一直发送的,我看看你说的校验问题 1a2b3c 发表于 2019-8-29 17:32
没有看明白楼主,先不看楼主代码,看下楼主人吧,
肯定是设计思路问题,数据是一直有还是随机有,还是不知 ...
数据一直有的,模块只要上电就一直发送,我知道肯定是我思路问题,所以才来求助坛友了^_^ 程序里有死等的都不是好程序 newywx 发表于 2019-8-29 18:34
数据一直有的,模块只要上电就一直发送,我知道肯定是我思路问题,所以才来求助坛友了^_^ ...
后面我回复你的那个帖子都给你指出来了问题了没有看??
你明知道串口数据会源源不断的接收到,那么不做思路去限制么?或者即使想你目前这样允许覆盖接收,类似环形缓冲区,但是你就得自己手动去搜索完整的数据帧,在你的缓冲区找到你要的一帧信息。 1a2b3c 发表于 2019-8-29 18:52
后面我回复你的那个帖子都给你指出来了问题了没有看??
你明知道串口数据会源源不断的接收到,那么不做 ...
正在看^_^ my_avr 发表于 2019-8-29 18:47
程序里有死等的都不是好程序
对的,得改 "中间差不多延时20秒的时间,"
{:funk:}{:funk:}{:funk:}{:funk:},你牛,我写的程序,除非是几个空操作的时间,其他一概不等的
向北 发表于 2019-8-29 17:47
我也好想遇到过,我用的串口1和串口2,串口2连了一块串口屏,不确定什么时候会用数据过来,关键是我还tm用 ...
我看论坛里有兄弟4个串口都用的,不知道他们是怎么防止类似问题的 cu_ice 发表于 2019-8-29 21:23
"中间差不多延时20秒的时间,"
,你牛,我写的程序,除非是几个空操作的时 ...
那类似的长时间延时用定时器? 定时器,查标志位 cu_ice 发表于 2019-8-29 21:32
定时器,查标志位
看来也得这样 程序结构建议:非阻塞状态机+队列,需要延时的如楼上:定时器+标志位 太牛逼离开20s你的单片机是出门拉屎去了吗 这个项目是自己做着玩 还是公司开发 怕是要重新推翻进行哦 自己主动玩的,不会有水平太差的,逻辑上有冲突
学习其实是世界上最痛苦的事 把串口优先级开最高 本帖最后由 newywx 于 2019-8-30 08:57 编辑
谢楼上几位,自己倒腾的 首先,不要用while(1);做循环。然后串口报文必须加报头及校验和,这样才能数据纠错,传输数据才可靠。 xuwuhan 发表于 2019-8-30 08:58
首先,不要用while(1);做循环。然后串口报文必须加报头及校验和,这样才能数据纠错,传输数据才可靠。 ...
谢兄弟回复,像22楼兄弟说的逻辑上有冲突,得好好理理 newywx 发表于 2019-8-30 09:12
谢兄弟回复,像22楼兄弟说的逻辑上有冲突,得好好理理
好好再看看,建议找个串口通讯带校验的例程看看 本帖最后由 xf331785508 于 2019-8-30 10:16 编辑
newywx 发表于 2019-8-29 21:29
那类似的长时间延时用定时器?
修级打怪方法 :
void func1( void )
{
lvDoWork1();
delay_ms(10);
lvDoWork2();
if(Condition == 1)
{
if(Condition2 == 2 )
{
lvDoWork3();
delay_ms(100);
lvDoWork4();
}
lvDoWork5();
}
}
void func2( void )
{
switch( gbStep )
{
case 0:
if( Condition == 1 )
{
DelayCount = 0; //方法一
TimerAsynEvent(eCounter, callBackFunc, para, Start); // 方法二
gbStep = 1;
}
break;
case 1:
if( DelayCounter >= 500)
{
//do something;
}
else
{
DelayCounter++;
}
if( AsynEventFlag ) //方法二
{
//do something
}
break;
default:
break;
}
} xf331785508 发表于 2019-8-30 10:14
修级打怪方法 :
谢谢,好好看看! 没空代码,只提建议:
1、不是紧急的事(特别是需要长时间处理的)不要放在中断中处理,中断占太长时间会影响别的中断响应。
2、可以将紧急的中断设置为高优先级(比如串口中断、定时器中断)。
3、串口要用中断来收发。串口接收是硬件自动的,本身不会丢失字节,只有程序没及时取走数据造成丢失。
串口发送是硬件的,是主动的操作,发送方不应该有任何丢失的说法。 太可怕了 用 delay 做20秒延时
延时这个最好改成定时器计数来做
串口数据要有个头来判断开始 然后缓存置0 开始接收数据
Delay1ms(20000); //等20秒
吓死人哦
没系统,就要学会用状态机 不说51,就算stm32我也不敢这么做。 不能这么死等的,或者周期check也行 huangqi412 发表于 2019-8-29 22:35
太牛逼离开20s你的单片机是出门拉屎去了吗
程序里面好像是20ms,楼主写出20S了{:lol:} 看错了,还真有给20秒的延时{:sweat:} 能否正常收到就看dma是如何处理的了,dma满了就会覆盖写入。 向北 发表于 2019-8-29 17:47
我也好想遇到过,我用的串口1和串口2,串口2连了一块串口屏,不确定什么时候会用数据过来,关键是我还tm用 ...
如果 AD 真的不能被打斷,那就只能用 DMA 接收串口數據,或者用外部芯片接收,譬如 CDCTL-B1.
如果你的串口速率足夠低,AD 關中斷的時間小於 1 個 byte 的接收時間,用中斷接收也可以。 dukelec 发表于 2019-11-29 19:04
如果 AD 真的不能被打斷,那就只能用 DMA 接收串口數據,或者用外部芯片接收,譬如 CDCTL-B1.
如果你的串 ...
STC没有DMA。。。我也没找到您说的那个芯片。。。 向北 发表于 2019-11-29 19:44
STC没有DMA。。。我也没找到您说的那个芯片。。。
是的,STC 沒 DMA.
我簽名就有它資料。
不過一般情況,ADC 是可以中斷的吧。 wxdn 发表于 2019-11-30 00:40
我的一个项目里是这么做的,由于收发都是定长的,就定义了两个uchar变量和一个接收标志位,其中一个变量是 ...
这个应该就是接收超时吧,接收不定时数据我就用这方式做的
页:
[1]