GUANG1967 发表于 2025-1-6 11:17:00

如何清空接收缓存返回的数据

需要用CAN发两个指令,但我只想读其中1个指令返回的内容。目前我的情况是一直发一条指令,读出的数据正常,但如果轮流发两条指令(两条指令都有返回数据:串口助手看到返回数据正常),但can读出的数据就有错误?

GUANG1967 发表于 2025-1-6 11:25:13

while(1)
{
   be=0;
   encoder();                      //读编码(0x60)
   CanSendMsg(0x141,TxData);       //发送数据到 ID = 0x141;
   delay_ms(10);

               
   CanReadMsg(pdat);               //接受返回数据
               
   RX=pdat;
   RX=pdat;
   RX=pdat;
   RX=pdat;      
   codedata = (RX | RX<<8 | RX<<16 | RX<<24);//合成long型
       

///////////////////////////////////////////////////////////////
   Cdata = (codedata + 0x30);
   decimal(0);                      //显示目前的
   delay_ms(300);   
///////////////////////////////////////////////////////////////
               
               
                        CanSendMsg(0x141,TxData);      //发送数据到ID = 0x141;
                        delay_ms(10);          
        } 最底下的数据不发送,读出的数据就是正常的,发送下面的数据,读出的数据就反复出现错误。

GUANG1967 发表于 2025-1-6 11:28:07

我想问题应该是出在can的设置里

GUANG1967 发表于 2025-1-6 11:28:25

//========================================================================
// 函数: u8 ReadReg(u8 addr)
// 描述: CAN功能寄存器读取函数。
// 参数: CAN功能寄存器地址.
// 返回: CAN功能寄存器数据.
// 版本: VER1.0
// 日期: 2020-11-16
// 备注:
//========================================================================
uint8 CanReadReg(uint8 addr)
{
uint8 dat;
CANAR = addr;
dat = CANDR;
return dat;
}






//========================================================================
// 函数: void WriteReg(u8 addr, u8 dat)
// 描述: CAN功能寄存器配置函数。
// 参数: CAN功能寄存器地址, CAN功能寄存器数据.
// 返回: none.
// 版本: VER1.0
// 日期: 2020-11-16
// 备注:
//========================================================================
void CanWriteReg(uint8 addr, uint8 dat)
{
CANAR = addr;
CANDR = dat;
}





//========================================================================
// 函数: void CanReadFifo(u8 *pdat)
// 描述: 读取CAN缓冲区数据函数。
// 参数: *pdat: 存放CAN缓冲区数据.
// 返回: none.
// 版本: VER1.0
// 日期: 2020-11-16
// 备注:
//========================================================================
void CanReadFifo(uint8 *pdat)
{
pdat= CanReadReg(RX_BUF0);
pdat= CanReadReg(RX_BUF1);
pdat= CanReadReg(RX_BUF2);
pdat= CanReadReg(RX_BUF3);

pdat= CanReadReg(RX_BUF0);
pdat= CanReadReg(RX_BUF1);
pdat= CanReadReg(RX_BUF2);
pdat= CanReadReg(RX_BUF3);

pdat= CanReadReg(RX_BUF0);
pdat= CanReadReg(RX_BUF1);
pdat = CanReadReg(RX_BUF2);
pdat = CanReadReg(RX_BUF3);

pdat= CanReadReg(RX_BUF0);
pdat= CanReadReg(RX_BUF1);
pdat= CanReadReg(RX_BUF2);
pdat= CanReadReg(RX_BUF3);
}







//========================================================================
// 函数: u16 CanReadMsg(u8 *pdat)
// 描述: CAN发送数据函数。
// 参数: *pdat: 接收数据缓冲区.
// 返回: CAN ID.
// 版本: VER1.0
// 日期: 2020-11-19
// 备注:
//========================================================================
uint16 CanReadMsg(uint8 *pdat)
{
uint8 i;
uint16 CanID;
uint8 buffer;

CanReadFifo(buffer);                              //读取CAN缓冲区数据函数
CanID = ((buffer << 8) + buffer) >> 5;      //16位ID
for(i=0;i<8;i++)
{
pdat = buffer;
}
return CanID;
}






//========================================================================
// 函数: void CanSendMsg(u16 canid, u8 *pdat)
// 描述: CAN发送数据函数。
// 参数: canid: CAN ID; *pdat: 发送数据缓冲区.
// 返回: none.
// 版本: VER1.0
// 日期: 2020-11-19
// 备注:
//========================================================================
void CanSendMsg(uint16 CAN_ID1, uint8 *TxData)       //*************************************
{
uint16 CanID1;

CanID1 = CAN_ID1 << 5;
CanWriteReg(TX_BUF0,0x08);               //bit7: 标准帧(0)/扩展帧(1), bit6: 数据帧(0)/远程帧(1), bit3~bit0: 数据长度(DLC)
CanWriteReg(TX_BUF1,(uint8)(CanID1>>8));
CanWriteReg(TX_BUF2,(uint8)CanID1);
CanWriteReg(TX_BUF3,TxData);

CanWriteReg(TX_BUF0,TxData);
CanWriteReg(TX_BUF1,TxData);
CanWriteReg(TX_BUF2,TxData);
CanWriteReg(TX_BUF3,TxData);

CanWriteReg(TX_BUF0,TxData);
CanWriteReg(TX_BUF1,TxData);
CanWriteReg(TX_BUF2,TxData);

CanWriteReg(TX_BUF3,0x00);
CanWriteReg(CMR ,0x04);//发起一次帧传输
}







//========================================================================
// 函数: void CANSetBaudrate()
// 描述: CAN总线波特率设置函数。
// 参数: none.
// 返回: none.
// 版本: VER1.0
// 日期: 2020-11-19
// 备注:
//========================================================================
void CANSetBaudrate()
{
CanWriteReg(BTR0,(SJW << 6) + BRP);
CanWriteReg(BTR1,(SAM << 7) + (TSG2 << 4) + TSG1);
}






//========================================================================
// 函数: void CANInit()
// 描述: CAN初始化函数。
// 参数: none.
// 返回: none.
// 版本: VER1.0
// 日期: 2020-11-19
// 备注:
//========================================================================
void CANInit()
{
CANEN = 1;          //CAN1模块使能
CANSEL = 0;         //选择CAN1模块
P_SW1 = (P_SW1 & ~(3<<4)) | (0<<4); //端口切换(CAN_Rx,CAN_Tx) 0x00:P0.0,P0.10x10:P5.0,P5.10x20:P4.2,P4.50x30:P7.0,P7.1

// CAN2EN = 1;         //CAN2模块使能
// CANSEL = 1;         //选择CAN2模块
// P_SW3 = (P_SW3 & ~(3)) | (0);       //端口切换(CAN_Rx,CAN_Tx) 0x00:P0.2,P0.30x01:P5.2,P5.30x02:P4.6,P4.70x03:P7.2,P7.3

CanWriteReg(MR,0x04);      //使能 Reset Mode
CANSetBaudrate();            //设置波特率

CanWriteReg(ACR0,0x00);      //总线验收代码寄存器
CanWriteReg(ACR1,0x00);
CanWriteReg(ACR2,0x00);
CanWriteReg(ACR3,0x00);
CanWriteReg(AMR0,0xFF);      //总线验收屏蔽寄存器
CanWriteReg(AMR1,0xFF);
CanWriteReg(AMR2,0xFF);
CanWriteReg(AMR3,0xFF);

CanWriteReg(IMR ,0xff);      //中断寄存器
CanWriteReg(ISR ,0xff);      //清中断标志
CanWriteReg(MR,0x00);      //退出 Reset Mode

CANICR = 0x02;               //CAN中断使能
}






//========================================================================
// 函数: void CANBUS_Interrupt(void) interrupt CAN_VECTOR
// 描述: CAN总线中断函数。
// 参数: none.
// 返回: none.
// 版本: VER1.0
// 日期: 2020-11-19
// 备注:
//========================================================================
void CANBUS_Interrupt(void) interrupt CAN1_VECTOR
{
u8 isr;
u8 arTemp;
arTemp = CANAR;            //CANAR现场保存,避免主循环里写完 CANAR 后产生中断,在中断里修改了 CANAR 内容

isr = CanReadReg(ISR);
if((isr & 0x04) == 0x04)   //TI
{
CANAR = ISR;
CANDR |= 0x04;            //CLR FLAG
}

if((isr & 0x08) == 0x08)//RI
{
CANAR = ISR;
CANDR |= 0x08;         //CLR FLAG

B_CanRead = 1;
}

if((isr & 0x40) == 0x40)//ALI
{
CANAR = ISR;
CANDR |= 0x40;         //CLR FLAG
}

if((isr & 0x20) == 0x20)   //EWI
{
CANAR = ISR;
CANDR |= 0x20;         //CLR FLAG
}

if((isr & 0x10) == 0x10)//EPI
{
CANAR = ISR;
CANDR |= 0x10;         //CLR FLAG
}

if((isr & 0x02) == 0x02)//BEI
{
CANAR = ISR;
CANDR |= 0x02;         //CLR FLAG
}

if((isr & 0x01) == 0x01)//DOI
{
CANAR = ISR;
CANDR |= 0x01;         //CLR FLAG
}

CANAR = arTemp;         //CANAR现场恢复
}


GUANG1967 发表于 2025-1-6 11:29:43

楼主有空能帮我看看吗?

GUANG1967 发表于 2025-1-6 11:42:42

我读出的数据就发给显示,一直发一条指令(底下的数据不发送),显示的数据显示正常,但如果轮流发两条指令,两条指令都有返回数据:串口助手看到返回数据都是正常的,我只想一直显示我第一调指令的返回数据,而不想管第二调指令的返回数据,要如何做?

GUANG1967 发表于 2025-1-6 13:36:52

就算两次发送的数据相同,can读来的数据也会出错(显示的数据出错)(用串口助手看到设备返回的数据是正常的)。

乘风飞扬 发表于 2025-1-6 13:45:04

CAN总线连续发送多帧数据的话,要等待上一帧数据发送完成,然后再发下一帧数据。
建议到官网下载最新版本的32G实验箱例程包,或者屠龙刀三例程包,参考里面的CAN总线收发例子:
https://www.stcai.com/syx

芯LYS 发表于 2025-1-6 14:42:41


实验箱 主控芯片使用32G12K128,可以做示波器、波形发生器、TFT彩屏显示、OLED 12864、LCD 12864 等,

范例程序 直接下载:

屠龙刀核心板 32G12K128为主控芯片的核心板,可作为简易示波器,USB总线通信,CAN/LIN总线通信
范例程序直接下载:


王昱顺 发表于 2025-1-6 16:56:26

GUANG1967 发表于 2025-1-6 11:42
我读出的数据就发给显示,一直发一条指令(底下的数据不发送),显示的数据显示正常,但如果轮流发两条指令 ...
我看你代码中的:

CanSendMsg(0x141,TxData);       //发送数据到 ID = 0x141;
delay_ms(10);
CanReadMsg(pdat);               //接受返回数据是直接使用了延时后读取,这样是不对的,因为不能保证此时是发送完成了还是没有。
我试过同时跟三个CAN设备通讯,收发都是正常的。
如果不想让系统卡住,就使用状态机。
然后发送的时候,使用(注意使用对应的)
if (B_Can1Send == 0) // 发送完成标志

同样的,接收的时候需要先判断
if (B_Can1Read)
{
B_Can1Read = 0;
n = CanReadMsg(CAN1_Rx); // 读取接收内容
for (can_cnt = 0; can_cnt < n; can_cnt++)
{
         Can_Dat_Handle(&CAN1_Rx);//数据解析部分,自行编写
}
}
来判断是否接收完成,否则就有可能造成你所述的这种混乱情况。

因为can部分是带有fifo的,所以,如果数据不是很长的话。可以全部发送完成后再处理接收数据,处理的时候依照ID进行区分就可以了
页: [1]
查看完整版本: 如何清空接收缓存返回的数据