笔记九:发送整形,长整形数据·实验<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
写这篇笔记是绝对需要的,一些眼睛犀利的朋友一定察觉到我之前所写的程式存在一个致命的弱点。那么它是什么呢?别急,只要通过两个简单的实验,大家一定会“噢”的明白的。
笔记八主要是针对两点而编写的,第一点就是发送整形数据,和另一点就是针对我之前写的进行深入的探索。那么开始吧:
实验内容:
节点一以每秒发送+1的数据给节点二,节点二将数据显示在数码管上,但是节点一的内容主要是整形数据。
编写程式的过程,节点1将整形数据拆分,然后赋值给发送缓冲寄存器然后发送数据,节点2将接收到的数据重新拼接,然后显示在数码管上。
节点一(发送)源码:
//00-整形数据发送实验(节点一).c
//发送角色
//akuei2 22-10-09
#include "reg52.h"
#include "sja1000.h"
#define uchar unsigned char
#define Length sizeof(unsigned int)
//IO声明
sbit SJACS=P2^0;
sbit SJARST=P2^3;
//数码管吗,位选码
uchar code Led_Code[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff};
uchar code Led_Select[]={0xef,0xdf,0xbf,0x7f};
//数据变量声明
uchar ACR[4],AMR[4],TXD_Buffer[13],RXD_Buffer[13],TXD_Data,RXD_Data;
unsigned int Sec,t0;
//函数声明
void Display(void);
void CAN_TXD(void);
//50微秒延迟函数
void Delay_50us(int t)
{
uchar j;
t--;
for(;t>0;t--)
for(j=19;j>0;j--);
}
//数据初始化函数
void Init_Data(void)
{
int i;
ACR[0]='C';
ACR[1]='A';
ACR[2]='N';
ACR[3]='1';
AMR[0]=0x00;
AMR[1]=0x00;
AMR[2]=0x00;
AMR[3]=0x03;
TXD_Buffer[0]=0x88;
TXD_Buffer[1]='C';
TXD_Buffer[2]='A';
TXD_Buffer[3]='N';
TXD_Buffer[4]='2';
TXD_Buffer[5]=TXD_Data;
TXD_Buffer[6]=0x00;
TXD_Buffer[7]=0x00;
TXD_Buffer[8]=0x00;
TXD_Buffer[9]=0x00;
TXD_Buffer[10]=0x00;
TXD_Buffer[11]=0x00;
TXD_Buffer[12]=0x00;
for(i=0;i<13;i++)
{
RXD_Buffer=0x00;
}
TXD_Data=0x00;
RXD_Data=0x00;
}
//CPU初始化函数
void Init_CPU(void)
{
TMOD=0x01;
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
TR0=1;
ET0=1;
SJACS=1;
SJARST=1;
//IT0=1;
//EX0=1;
EA=1;
}
//CAN初始化函数
void Init_CAN(void)
{
unsigned char bdata temp; //建立存储在bdata中的临时变量temp
do
{
MODR=0x09;
temp=MODR; //模式寄存器-设置复位模式而且单验收滤波模式
}
while(!(temp&0x01)); //判断
CDR=0x88; //时钟分频寄存器-设置PeliCAN模式,Clock off有效
BTR0=0x31; //总线时序寄存器-波特率为10kbps
BTR1=0x1c;
IER=0x01; //中断使能寄存器-全部关闭
OCR=0xaa; //输出控制寄存器-借签...
CMR=0x04; //命令寄存器-释放RXFIF0
ACR0=ACR[0]; //接收代码寄存器-本节点地址位CAN0
ACR1=ACR[1];
ACR2=ACR[2];
ACR3=ACR[3];
AMR0=AMR[0]; //接收屏蔽寄存器-无任何屏蔽
AMR1=AMR[1];
AMR2=AMR[2];
AMR3=AMR[3]; //最后两位为无用位,必须设置为逻辑1
do
{
MODR=0x08;
temp=MODR; //模式寄存器-退出复位模式,保持单验收滤波模式
}
while(temp&0x01); //判断...
}
//主函数
void main(void)
{
Init_Data();
Init_CPU();
Init_CAN();
while(1)
{
Display();
}
}
//数码管显示函数
void Display(void)
{
int Digit[4],i;
Digit[3]=Sec/1000; //第一个数码管取千位
Digit[2]=Sec%1000/100; //第二个数码管取百位
Digit[1]=Sec%100/10; //第三个数码管取十位
Digit[0]=Sec%10; //第四个数码管取个位
for(i=0;i<4;i++)
{
P0=Led_Code[Digit[3-i]]; //送数码管码
P2=Led_Select; //送位选码
Delay_50us(20); //延迟1微秒
}
}
//节点发送函数
void CAN_TXD(void)
{
unsigned char bdata temp;
do
{
temp=SR; //判断报文接收完毕?
}
while(temp&0x10); //SR.4=0 发送闲置,SR.4=1 发送状态中
do
{
temp=SR; //判断最后报文请求?
}
while(!(temp&0x08)); //SR.3=0 没有余报文请求,SR.3=1 还存在报文请求
do
{
temp=SR; //判断TXFIFO是否锁定?
}
while(!(temp&0x04)); //SR.2=0 锁定,SR.2=1 开放
TBSR0=TXD_Buffer[0];
TBSR1=TXD_Buffer[1];
TBSR2=TXD_Buffer[2];
TBSR3=TXD_Buffer[3];
TBSR4=TXD_Buffer[4];
TBSR5=TXD_Buffer[5];
TBSR6=TXD_Buffer[6];
TBSR7=TXD_Buffer[7];
TBSR8=TXD_Buffer[8];
TBSR9=TXD_Buffer[9];
TBSR10=TXD_Buffer[10];
TBSR11=TXD_Buffer[11];
TBSR12=TXD_Buffer[12];
CMR=0x01; //命令寄存器-发送请求
}
//拆分函数
void Split()
{
unsigned int i,temp;
temp=Sec;
for(i=0;i<Length;i++) // 将变量a的值,逐个字节拆分然后复制temp
{
TXD_Buffer[i+5]=temp;
temp=temp>>8;
}
}
//定时器0中断函数
void Ir_T0(void) interrupt 1
{
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
t0++;
if(t0>=20)
{
t0=0;
Sec++;
Split();
CAN_TXD();
}
}
节点二(接收)源码:
//01-整形发送实验(节点二).c
//接收角色
//akuei2 22-10-09
#include "reg52.h"
#include "sja1000.h"
#define uchar unsigned char
#define Length sizeof(int)
//IO口定义
sbit SJACS=P2^0;
sbit SJARST=P2^3;
//数码管码,位选码
uchar code Led_Code[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff};
uchar code Led_Select[]={0xef,0xdf,0xbf,0x7f};
//变量声明
uchar ACR[4],AMR[4],TXD_Buffer[13],RXD_Buffer[13],TXD_Data;
unsigned int RXD_Data;
bit Flag_RXD;
//函数声明
void Display(void);
void CAN_RXD(void);
int Joint(void);
//50微秒延迟函数
void Delay_50us(int t)
{
uchar j;
t--;
for(;t>0;t--)
for(j=19;j>0;j--);
}
//数据初始化函数
void Init_Data(void)
{
int i;
ACR[0]='C';
ACR[1]='A';
ACR[2]='N';
ACR[3]='2';
AMR[0]=0x00;
AMR[1]=0x00;
AMR[2]=0x00;
AMR[3]=0x03;
for(i=0;i<13;i++)
{
RXD_Buffer=0x00;
}
TXD_Data=0x00;
RXD_Data=0x00;
}
//CPU初始化函数
void Init_CPU(void)
{
SJACS=1;
SJARST=1;
IT1=0;
EX1=1;
EA=1;
}
//节点初始化
void Init_CAN(void)
{
unsigned char bdata temp; //建立存储在bdata中的临时变量temp
do
{
MODR=0x09;
temp=MODR; //模式寄存器-设置复位模式而且单验收滤波模式
}
while(!(temp&0x01)); //判断
CDR=0x88; //时钟分频寄存器-设置PeliCAN模式,Clock off有效
BTR0=0x31; //总线时序寄存器-波特率为10kbps
BTR1=0x1c;
IER=0x01; //中断使能寄存器-接收中断使能
OCR=0xaa; //输出控制寄存器-借签...
CMR=0x04; //命令寄存器-释放RXFIF0
ACR0=ACR[0]; //接收代码寄存器-本节点地址位CAN0
ACR1=ACR[1];
ACR2=ACR[2];
ACR3=ACR[3];
AMR0=AMR[0]; //接收屏蔽寄存器-无任何屏蔽
AMR1=AMR[1];
AMR2=AMR[2];
AMR3=AMR[3]; //最后两位为无用位,必须设置为逻辑1
do
{
MODR=0x08;
temp=MODR; //模式寄存器-推出复位模式,保持单验收滤波模式
}
while(temp&0x01); //判断...
}
//主函数
void main(void)
{
Init_Data();
Init_CPU();
Init_CAN();
while(1)
{
Display();
}
}
//数码管显示函数
void Display(void)
{
int Digit[4],i;
Digit[3]=RXD_Data/1000; //第一个数码管取千位
Digit[2]=RXD_Data%1000/100; //第二个数码管取百位
Digit[1]=RXD_Data%100/10; //第三个数码管取十位
Digit[0]=RXD_Data%10; //第四个数码管取个位
for(i=0;i<4;i++)
{
P0=Led_Code[Digit[3-i]]; //送数码管码
P2=Led_Select; //送位选码
Delay_50us(20); //延迟1微秒
}
}
//节点接收函数
void CAN_RXD(void)
{
unsigned char temp;
temp = IR;
if( temp & 0x01) //判断是否接收中断
{
RXD_Buffer[0]=RBSR0; //读取RXFIFO
RXD_Buffer[1]=RBSR1;
RXD_Buffer[2]=RBSR2;
RXD_Buffer[3]=RBSR3;
RXD_Buffer[4]=RBSR4;
RXD_Buffer[5]=RBSR5;
RXD_Buffer[6]=RBSR6;
RXD_Buffer[7]=RBSR7;
RXD_Buffer[8]=RBSR8;
RXD_Buffer[9]=RBSR9;
RXD_Buffer[10]=RBSR10;
RXD_Buffer[11]=RBSR11;
RXD_Buffer[12]=RBSR12;
CMR = 0X04; //释放RXFIFO中的空间
temp = ALC; //释放仲裁随时捕捉寄存器
temp = ECC; //释放错误代码捕捉寄存器
}
IER = 0x01;// .0=1--接收中断使能;
}
//拼接函数
int Joint(void)
{
unsigned int a,i;
for(i=0;i<Length;i++) //RXD_Buffer从RXFIFO读取到的值,进行恢复后赋值予a
{
a=a|RXD_Buffer[Length-i-1+5];
if(i!=1)
a=a<<8;
}
return a;
}
//接收中断函数
void Ir_EX1(void) interrupt 2
{
EA=0;
EX1=0;
CAN_RXD();
Joint();
EX1=1;
EA=1;
}
===========================================================================================
当将程式下载到CAN学习板观察后,你会发现到发送端没有问题,而接受端却出现爆炸性的问题,数码管不能正常显示从节点1接收来的值?其实这程式是没有错误的,而错误仅发生在编程的次序上面。到底哪里发生问题了呢?
我们再接下去观察以下已经修改过的代码。
节点一(发送)源码:
//00-整形数据发送实验(节点一).c
//发送角色
//akuei2 22-10-09
#include "reg52.h"
#include "sja1000.h"
#define uchar unsigned char
#define Length sizeof(unsigned int)
//IO声明
sbit SJACS=P2^0;
sbit SJARST=P2^3;
//数码管吗,位选码
uchar code Led_Code[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff};
uchar code Led_Select[]={0xef,0xdf,0xbf,0x7f};
//数据变量声明
uchar ACR[4],AMR[4],TXD_Buffer[13],RXD_Buffer[13],TXD_Data,RXD_Data;
unsigned int Sec,t0;
bit Flag_TXD;
//函数声明
void Display(void);
void CAN_TXD(void);
void Split();
//50微秒延迟函数
void Delay_50us(int t)
{
uchar j;
t--;
for(;t>0;t--)
for(j=19;j>0;j--);
}
//数据初始化函数
void Init_Data(void)
{
int i;
ACR[0]='C';
ACR[1]='A';
ACR[2]='N';
ACR[3]='1';
AMR[0]=0x00;
AMR[1]=0x00;
AMR[2]=0x00;
AMR[3]=0x03;
TXD_Buffer[0]=0x88;
TXD_Buffer[1]='C';
TXD_Buffer[2]='A';
TXD_Buffer[3]='N';
TXD_Buffer[4]='2';
TXD_Buffer[5]=TXD_Data;
TXD_Buffer[6]=0x00;
TXD_Buffer[7]=0x00;
TXD_Buffer[8]=0x00;
TXD_Buffer[9]=0x00;
TXD_Buffer[10]=0x00;
TXD_Buffer[11]=0x00;
TXD_Buffer[12]=0x00;
for(i=0;i<13;i++)
{
RXD_Buffer=0x00;
}
TXD_Data=0x00;
RXD_Data=0x00;
}
//CPU初始化函数
void Init_CPU(void)
{
TMOD=0x01;
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
TR0=1;
ET0=1;
SJACS=1;
SJARST=1;
//IT0=1;
//EX0=1;
EA=1;
}
//节点初始化函数
void Init_CAN(void)
{
unsigned char bdata temp; //建立存储在bdata中的临时变量temp
do
{
MODR=0x09;
temp=MODR; //模式寄存器-设置复位模式而且单验收滤波模式
}
while(!(temp&0x01)); //判断
CDR=0x88; //时钟分频寄存器-设置PeliCAN模式,Clock off有效
BTR0=0x31; //总线时序寄存器-波特率为10kbps
BTR1=0x1c;
IER=0x01; //中断使能寄存器-全部关闭
OCR=0xaa; //输出控制寄存器-借签...
CMR=0x04; //命令寄存器-释放RXFIF0
ACR0=ACR[0]; //接收代码寄存器
ACR1=ACR[1];
ACR2=ACR[2];
ACR3=ACR[3];
AMR0=AMR[0]; //接收屏蔽寄存器-无任何屏蔽
AMR1=AMR[1];
AMR2=AMR[2];
AMR3=AMR[3]; //最后两位为无用位,必须设置为逻辑1
do
{
MODR=0x08;
temp=MODR; //模式寄存器-退出复位模式,保持单验收滤波模式
}
while(temp&0x01); //判断...
}
//主函数
void main(void)
{
Init_Data();
Init_CPU();
Init_CAN();
while(1)
{
Display();
if(Flag_TXD)
{
Flag_TXD=0;
Split();
CAN_TXD();
}
}
}
//数码管显示函数
void Display(void)
{
int Digit[4],i;
Digit[3]=Sec/1000; //第一个数码管取千位
Digit[2]=Sec%1000/100; //第二个数码管取百位
Digit[1]=Sec%100/10; //第三个数码管取十位
Digit[0]=Sec%10; //第四个数码管取个位
for(i=0;i<4;i++)
{
P0=Led_Code[Digit[3-i]]; //送数码管码
P2=Led_Select; //送位选码
Delay_50us(20); //延迟1微秒
}
}
void CAN_TXD(void)
{
unsigned char bdata temp;
do
{
temp=SR; //判断报文接收完毕?
}
while(temp&0x10); //SR.4=0 发送闲置,SR.4=1 发送状态中
do
{
temp=SR; //判断最后报文请求?
}
while(!(temp&0x08)); //SR.3=0 没有余报文请求,SR.3=1 还存在报文请求
do
{
temp=SR; //判断TXFIFO是否锁定?
}
while(!(temp&0x04)); //SR.2=0 锁定,SR.2=1 开放
TBSR0=TXD_Buffer[0];
TBSR1=TXD_Buffer[1];
TBSR2=TXD_Buffer[2];
TBSR3=TXD_Buffer[3];
TBSR4=TXD_Buffer[4];
TBSR5=TXD_Buffer[5];
TBSR6=TXD_Buffer[6];
TBSR7=TXD_Buffer[7];
TBSR8=TXD_Buffer[8];
TBSR9=TXD_Buffer[9];
TBSR10=TXD_Buffer[10];
TBSR11=TXD_Buffer[11];
TBSR12=TXD_Buffer[12];
CMR=0x01; //命令寄存器-发送请求
}
void Split()
{
unsigned int i,temp;
temp=Sec;
for(i=0;i<Length;i++) // 将变量a的值,逐个字节拆分然后复制temp
{
TXD_Buffer[i+5]=temp;
temp=temp>>8;
}
}
//定时器0中断函数
void Ir_T0(void) interrupt 1
{
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
t0++;
if(t0>=20)
{
t0=0;
Sec++;
Flag_TXD=1;
}
}
===========================================================================================
节点二(接收)源码
//01-整形发送实验(节点二).c
//接收角色
//akuei2 22-10-09
#include "reg52.h"
#include "sja1000.h"
#define uchar unsigned char
#define Length sizeof(int)
//IO口定义
sbit SJACS=P2^0;
sbit SJARST=P2^3;
//数码管码,位选码
uchar code Led_Code[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff};
uchar code Led_Select[]={0xef,0xdf,0xbf,0x7f};
//变量声明
uchar ACR[4],AMR[4],TXD_Buffer[13],RXD_Buffer[13],TXD_Data;
unsigned int RXD_Data;
bit Flag_RXD;
//函数声明
void Display(void);
void CAN_RXD(void);
int Joint(void);
//50微秒延迟函数
void Delay_50us(int t)
{
uchar j;
t--;
for(;t>0;t--)
for(j=19;j>0;j--);
}
//数据初始化函数
void Init_Data(void)
{
int i;
ACR[0]='C';
ACR[1]='A';
ACR[2]='N';
ACR[3]='2';
AMR[0]=0x00;
AMR[1]=0x00;
AMR[2]=0x00;
AMR[3]=0x03;
for(i=0;i<13;i++)
{
RXD_Buffer=0x00;
}
TXD_Data=0x00;
RXD_Data=0x00;
}
//CPU初始化函数
void Init_CPU(void)
{
SJACS=1;
SJARST=1;
IT1=0;
EX1=1;
EA=1;
}
//节点初始化
void Init_CAN(void)
{
unsigned char bdata temp; //建立存储在bdata中的临时变量temp
do
{
MODR=0x09;
temp=MODR; //模式寄存器-设置复位模式而且单验收滤波模式
}
while(!(temp&0x01)); //判断
CDR=0x88; //时钟分频寄存器-设置PeliCAN模式,Clock off有效
BTR0=0x31; //总线时序寄存器-波特率为10kbps
BTR1=0x1c;
IER=0x01; //中断使能寄存器-接收中断使能
OCR=0xaa; //输出控制寄存器-借签...
CMR=0x04; //命令寄存器-释放RXFIF0
ACR0=ACR[0]; //接收代码寄存器-本节点地址位CAN0
ACR1=ACR[1];
ACR2=ACR[2];
ACR3=ACR[3];
AMR0=AMR[0]; //接收屏蔽寄存器-无任何屏蔽
AMR1=AMR[1];
AMR2=AMR[2];
AMR3=AMR[3]; //最后两位为无用位,必须设置为逻辑1
do
{
MODR=0x08;
temp=MODR; //模式寄存器-推出复位模式,保持单验收滤波模式
}
while(temp&0x01); //判断...
}
//主函数
void main(void)
{
Init_Data();
Init_CPU();
Init_CAN();
while(1)
{
Display();
if(Flag_RXD)
{
Flag_RXD=0;
RXD_Data=Joint();
}
}
}
//数码管显示函数
void Display(void)
{
int Digit[4],i;
Digit[3]=RXD_Data/1000; //第一个数码管取千位
Digit[2]=RXD_Data%1000/100; //第二个数码管取百位
Digit[1]=RXD_Data%100/10; //第三个数码管取十位
Digit[0]=RXD_Data%10; //第四个数码管取个位
for(i=0;i<4;i++)
{
P0=Led_Code[Digit[3-i]]; //送数码管码
P2=Led_Select; //送位选码
Delay_50us(20); //延迟1微秒
}
}
//节点接收函数
void CAN_RXD(void)
{
unsigned char temp;
temp = IR;
if( temp & 0x01) //判断是否接收中断
{
RXD_Buffer[0]=RBSR0; //读取RXFIFO
RXD_Buffer[1]=RBSR1;
RXD_Buffer[2]=RBSR2;
RXD_Buffer[3]=RBSR3;
RXD_Buffer[4]=RBSR4;
RXD_Buffer[5]=RBSR5;
RXD_Buffer[6]=RBSR6;
RXD_Buffer[7]=RBSR7;
RXD_Buffer[8]=RBSR8;
RXD_Buffer[9]=RBSR9;
RXD_Buffer[10]=RBSR10;
RXD_Buffer[11]=RBSR11;
RXD_Buffer[12]=RBSR12;
CMR = 0X04; //释放RXFIFO中的空间
temp = ALC; //释放仲裁随时捕捉寄存器
temp = ECC; //释放错误代码捕捉寄存器
}
IER = 0x01;// .0=1--接收中断使能;
}
//拼接函数
int Joint(void)
{
unsigned int a,i;
for(i=0;i<Length;i++) //RXD_Buffer从RXFIFO读取到的值,进行恢复后赋值予a
{
a=a|RXD_Buffer[Length-i-1+5];
if(i!=1)
a=a<<8;
}
return a;
}
//接收中断函数
void Ir_EX1(void) interrupt 2
{
EA=0;
EX1=0;
CAN_RXD();
Flag_RXD=1;
EX1=1;
EA=1;
}
https://static.assets-stash.eet-china.com/album/old-resources/2009/10/25/6817475c-1da7-4507-b5b4-47506c1704eb.rar" target=_blank>
===========================================================================================
再尝试将这个程式下载到CAN学习板上,这时你会发现接收方(节点二)已经是正常显示了,以上的源码在修改中我主要加了标志位,实验证明了,标志位有效避免了由于中断服务频发发生所引起的接收错误,这怎么说?...在前段源码中,当触发中断时,由于给与CAN FIFO赋值的时间不足,前一个赋值的动作还来不及完成,然后再进行触发中断 FIFO的赋值就产生了赋值的错误。由于标志位给与了有效的执行次序,这也是为什么标志位可以避免了前段源码所发生的问题。
这就是我所犯下的编程大罪,(呜呜呜,又误认子弟了),真的以死谢罪也不够....呜呜呜!我郑重的反省后,发至内心的告诉大家,在编写CAN接收和发送函数时,加入标志位可以使好执行次序,不然的话报文发送|接收错误很容易发生。
源码下载
文章评论(0条评论)
登录后参与讨论