多个STC12C5A60S2单片机如何连入CAN总线?

多个STC12C5A60S2单片机如何连入CAN总线?,第1张

这个问题比较复杂,首先STC12C5A60S2是一款不带CAN总线的单片机,需要外接CAN总线控制器,例如SJA1000,好像是飞利浦的芯片,与单片机并行通讯,协议很复杂,所以我建议用带CAN总线的单片机,例如STM8系列,C8051系列,这样外接一个CAN总线收发器就行了,简单方便

//仅供参考
#include <reg52h> #include <intrinsh> typedef unsigned char uchar; typedef unsigned char uint; //IO 端 口 定 义 sbit MISO =P1^2; sbit MOSI =P3^2; sbit SCK =P1^6; sbit CE =P1^5; sbit CSN =P1^7; sbit IRQ =P1^3; // 数 码 管 0-9 编 码 uchar seg[10]={0xC0,0xCF,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90}; //0~~9 段码 uchar TxBuf[32]= { 0x01,0x02,0x03,0x4,0x05,0x06,0x07,0x08, 0x09,0x10,0x11,0x12,0x13,0x14,0x15,0x16, 0x17,0x18,0x19,0x20,0x21,0x22,0x23,0x24, 0x25,0x26,0x27,0x28,0x29,0x30,0x31,0x32, }; // // 按 键 sbit KEY1=P3^6; sbit KEY2=P3^7; // 数 码 管 位 选 sbit led1=P2^1; sbit led0=P2^0; sbit led2=P2^2; sbit led3=P2^3; //NRF24L01 #define TX_ADR_WIDTH 5 // 5 uints TX address width #define RX_ADR_WIDTH 5 // 5 uints RX address width #define TX_PLOAD_WIDTH 32 // 20 uints TX payload #define RX_PLOAD_WIDTH 32 // 20 uints TX payload uint const TX_ADDRESS[TX_ADR_WIDTH]= {0x34,0x43,0x10,0x10,0x01}; //本地地址 uint const RX_ADDRESS[RX_ADR_WIDTH]= {0x34,0x43,0x10,0x10,0x01}; //接收地址 //NRF24L01 寄 存 器 指 令 #define READ_REG 0x00 // 读寄存器指令 #define WRITE_REG 0x20 // 写寄存器指令 #define RD_RX_PLOAD 0x61 // 读取接收数据指令 #define WR_TX_PLOAD 0xA0 // 写待发数据指令 #define FLUSH_TX 0xE1 // 冲洗发送 FIFO 指令 #define FLUSH_RX 0xE2 // 冲洗接收 FIFO 指令 #define REUSE_TX_PL 0xE3 // 定义重复装载数据指令 #define NOP 0xFF // 保留 //SPI(nRF24L01) 寄 存 器 地 址 #define CONFIG 0x00 // 配置收发状态,CRC 校验模式以及收发状态响应方式 #define EN_AA 0x01 // 自动应答功能设置 #define EN_RXADDR 0x02 // 可用信道设置 #define SETUP_AW 0x03 // 收发地址宽度设置 #define SETUP_RETR 0x04 // 自动重发功能设置 #define RF_CH 0x05 // 工作频率设置 #define RF_SETUP 0x06 // 发射速率、功耗功能设置 #define STATUS 0x07 // 状态寄存器 #define OBSERVE_TX 0x08 // 发送监测功能 #define CD 0x09 // 地址检测 #define RX_ADDR_P0 0x0A // 频道 0 接收数据地址 #define RX_ADDR_P1 0x0B // 频道 1 接收数据地址 #define RX_ADDR_P2 0x0C // 频道 2 接收数据地址 #define RX_ADDR_P3 0x0D // 频道 3 接收数据地址 #define RX_ADDR_P4 0x0E // 频道 4 接收数据地址 #define RX_ADDR_P5 0x0F // 频道 5 接收数据地址 #define TX_ADDR 0x10 // 发送地址寄存器 #define RX_PW_P0 0x11 // 接收频道 0 接收数据长度 #define RX_PW_P1 0x12 // 接收频道 0 接收数据长度 #define RX_PW_P2 0x13 // 接收频道 0 接收数据长度 #define RX_PW_P3 0x14 // 接收频道 0 接收数据长度 #define RX_PW_P4 0x15 // 接收频道 0 接收数据长度 #define RX_PW_P5 0x16 // 接收频道 0 接收数据长度 #define FIFO_STATUS 0x17 // FIFO 栈入栈出状态寄存器设置 // void Delay(unsigned int s); void inerDelay_us(unsigned char n); void init_NRF24L01(void); uint SPI_RW(uint uchar); uchar SPI_Read(uchar reg); void SetRX_Mode(void); uint SPI_RW_Reg(uchar reg, uchar value); uint SPI_Read_Buf(uchar reg, uchar pBuf, uchar uchars); uint SPI_Write_Buf(uchar reg, uchar pBuf, uchar uchars); unsigned char nRF24L01_RxPacket(unsigned char rx_buf); void nRF24L01_TxPacket(unsigned char tx_buf); // 长 延 时 void Delay(unsigned int s) { unsigned int i; for(i=0; i<s; i++); for(i=0; i<s; i++); } // uint bdata sta; //状态标志 sbit RX_DR =sta^6; sbit TX_DS =sta^5; sbit MAX_RT =sta^4; / /延时函数 / / void inerDelay_us(unsigned char n) { for(;n>0;n--) _nop_(); } // /NRF24L01 初始化 // / void init_NRF24L01(void) { inerDelay_us(100); CE=0; // chip enable CSN=1; // Spi disable SCK=0; // Spi clock line init high SPI_Write_Buf(WRITE_REG + TX_ADDR, TX_ADDRESS, TX_ADR_WIDTH); // 写本地地址 SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, RX_ADDRESS, RX_ADR_WIDTH); // 写接收端地址 SPI_RW_Reg(WRITE_REG + EN_AA, 0x01); // 频道 0 自动 ACK 应 答 允 许 SPI_RW_Reg(WRITE_REG + EN_RXADDR, 0x01); // 允许接收地址只有频道 0,如 果需要多频道可以参考 Page21 SPI_RW_Reg(WRITE_REG + RF_CH, 0); // 设置信道工作为 24GHZ, 收发必 须一致 SPI_RW_Reg(WRITE_REG + RX_PW_P0, RX_PLOAD_WIDTH); //设置接收数据长度, 本次设置为 32 字节 SPI_RW_Reg(WRITE_REG + RF_SETUP, 0x07); //设置发射速率为 1MHZ,发射 功率为最大值 0dB SPI_RW_Reg(WRITE_REG + CONFIG, 0x0e); // IRQ 收发完成中断响应,16 位 CRC,主发送 } / /函数:uint SPI_RW(uint uchar) /功能:NRF24L01 的 SPI 写时序 / / uint SPI_RW(uint uchar) { uint bit_ctr; for(bit_ctr=0;bit_ctr<8;bit_ctr++) // output 8-bit { MOSI = (uchar & 0x80); // output 'uchar', MSB to MOSI uchar = (uchar << 1); // shift next bit into MSB SCK = 1; // Set SCK high uchar |= MISO; // capture current MISO bit SCK = 0; // then set SCK low again } return(uchar); // return read uchar } / /函数:uchar SPI_Read(uchar reg) /功能:NRF24L01 的 SPI 时序 / / uchar SPI_Read(uchar reg) { uchar reg_val; CSN = 0; SPI_RW(reg); reg_val = SPI_RW(0); CSN = 1; // CSN low, initialize SPI communication // Select register to read from // then read registervalue // CSN high, terminate SPI communication return(reg_val); // return register value } / / /功能:NRF24L01 读写寄存器函数 / / uint SPI_RW_Reg(uchar reg, uchar value) { uint status; CSN = 0; status = SPI_RW(reg); SPI_RW(value); CSN = 1; return(status); // CSN low, init SPI transaction // select register // and write value to it // CSN high again // return nRF24L01 status uchar } / / /函数:uint SPI_Read_Buf(uchar reg, uchar pBuf, uchar uchars) /功能: 用于读数据,reg:为寄存器地址,pBuf:为待读出数据地址,uchars:读出数据的 个数 / / uint SPI_Read_Buf(uchar reg, uchar pBuf, uchar uchars) { uint status,uchar_ctr; CSN = 0; status = SPI_RW(reg); // Set CSN low, init SPI tranaction // Select register to write to and read status uchar for(uchar_ctr=0;uchar_ctr<uchars;uchar_ctr++) pBuf[uchar_ctr] = SPI_RW(0); // CSN = 1; return(status); // return nRF24L01 status uchar } / /函数:uint SPI_Write_Buf(uchar reg, uchar pBuf, uchar uchars) /功能: 用于写数据:为寄存器地址,pBuf:为待写入数据地址,uchars:写入数据的个数 / / uint SPI_Write_Buf(uchar reg, uchar pBuf, uchar uchars) { uint status,uchar_ctr; CSN = 0; //SPI 使能 status = SPI_RW(reg); for(uchar_ctr=0; uchar_ctr<uchars; uchar_ctr++) // SPI_RW(pBuf++); CSN = 1; //关闭 SPI return(status); // } / / /函数:void SetRX_Mode(void) /功能:数据接收配置 / / void SetRX_Mode(void) { CE=0; SPI_RW_Reg(WRITE_REG + CONFIG, 0x0f); // IRQ 收发完成中断响应,16 位 CRC ,主接收 CE = 1; inerDelay_us(130); } / / /函数:unsigned char nRF24L01_RxPacket(unsigned char rx_buf) /功能:数据读取后放如 rx_buf 接收缓冲区中 / / unsigned char nRF24L01_RxPacket(unsigned char rx_buf) { unsigned char revale=0; sta=SPI_Read(STATUS); // 读取状态寄存其来判断数据接收状况 if(RX_DR) // 判断是否接收到数据 { CE = 0; //SPI 使能 SPI_Read_Buf(RD_RX_PLOAD,rx_buf,TX_PLOAD_WIDTH);// read receive payload from RX_FIFO buffer revale =1; //读取数据完成标志 } SPI_RW_Reg(WRITE_REG+STATUS,sta); //接收到数据后 RX_DR,TX_DS,MAX_PT 都置高为 1,通过写 1 来清楚中断标志 return revale; } / /函数:void nRF24L01_TxPacket(unsigned char tx_buf) /功能:发送 tx_buf 中数据 / / void nRF24L01_TxPacket(unsigned char tx_buf) { CE=0; //StandBy I 模式 SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, TX_ADDRESS, TX_ADR_WIDTH); // 装载接收端地址 SPI_Write_Buf(WR_TX_PLOAD, tx_buf, TX_PLOAD_WIDTH); // 装 载 数 据 // SPI_RW_Reg(WRITE_REG + CONFIG, 0x0e); // IRQ 收发完成中断响应,16 位 CRC,主发送 CE=1; //置高 CE,激发数据发送 inerDelay_us(10); } // 主 函 数 void main(void) { uchar temp =0; init_NRF24L01() ; led0=0;led1=0;led2=0;led3=0; P0=0x00; nRF24L01_TxPacket(TxBuf); // Transmit Tx buffer data Delay(6000); P0=0xBF; while(1) { if(temp<4) { switch(temp) { case 1: P0= 0xBF; break; case 2: P0= 0xf7; case break; 3: P0= 0xFE; break; default: break; } } if(temp==3) { temp=0; } nRF24L01_TxPacket(TxBuf); // Transmit Tx buffer data Delay(20000); SPI_RW_Reg(WRITE_REG+STATUS,0XFF); temp++; } }

#include <at89x51h>
#include "SJA1000_PELIh"
sfr WDT_CONTR = 0xe1; //STC单片机的看门狗所用寄存器
//
//按键与LED灯定义
//
#define LED0 P1_0
#define LED1 P1_1
#define LED2 P1_2
#define LED3 P1_3
#define KEY0 P1_4
#define KEY1 P1_5
#define KEY2 P1_6
#define KEY3 P1_7
//
//引用的外部变量声明
//
extern bit g_RiFlag; //CAN总线接收全局标志位声明
extern unsigned char TX[11]; //发送临时缓冲区声明
extern unsigned char RX[11]; //接收临时缓冲区声明
//
//引用的外部函数声明
//
extern void SJAInit(void); //SJA1000初始化函数声明
extern bit SJASendData(unsigned char SendDataBuf); //SJA1000低层发送函数声明
extern bit SJAReceData(unsigned char ReceiveDataBuf);//SJA1000低层接收函数声明
//
//全局变量声明
//
unsigned char code LEDstyle[4][11] = { {0x08,0xff,0xff,0xfe,0xfd,0xfb,0xf7,0xf7,0xfb,0xfd,0xfe},
{0x08,0xff,0xff,0xf9,0xf6,0xf9,0xf6,0xf9,0xf6,0xf9,0xf6},
{0x08,0xff,0xff,0xf1,0xf2,0xf4,0xf8,0xf1,0xf2,0xf4,0xf8},
{0x08,0xff,0xff,0xfc,0xf9,0xf3,0xf6,0xfc,0xf9,0xf3,0xf6}
} ;
//帧类型及长度,帧ID高8位,帧ID低3位,一帧中0-8个字节数据
//
//函数声明
//
void RS232Init(void); //串口初始化函数声明
void RS232Send(unsigned char tempdata); //串口发送函数声明
void DelayTime (unsigned char times); //延时函数声明
void CANSend(unsigned char style); //CAN总线发送函数声明
void CANRece(void); //CAN总线接收函数声明
//
//主函数
//
void main(void)
{
P1 = 0xff;
RS232Init(); //串口初始化,19200,1停止位,没校验
SJAInit(); //SJA初始化
//WDT_CONTR = 0x3c; //STC单片机的看门狗,喂狗
EA = 1;
while(1)
{
if (KEY0 ==0) { while (!KEY0); CANSend(0); } //KEY0按下,则发送流水灯花式0
if (KEY1 ==0) { while (!KEY1); CANSend(1); } //KEY1按下,则发送流水灯花式1
if (KEY2 ==0) { while (!KEY2); CANSend(2); } //KEY2按下,则发送流水灯花式2
if (KEY3 ==0) { while (!KEY3); CANSend(3); } //KEY3按下,则发送流水灯花式3

if (g_RiFlag) { g_RiFlag = 0; CANRece(); } //全局中断标志位如为1,则接收并处理
//WDT_CONTR = 0x3c; //STC单片机的喂狗,用S5X不用加此句
}
} //主程序结束
///
//CAN发送处理函数
///
void CANSend(unsigned char style)
{
TX[0] = LEDstyle[style][0];
TX[1] = LEDstyle[style][1];
TX[2] = LEDstyle[style][2];
TX[3] = LEDstyle[style][3];
TX[4] = LEDstyle[style][4];
TX[5] = LEDstyle[style][5];
TX[6] = LEDstyle[style][6];
TX[7] = LEDstyle[style][7];
TX[8] = LEDstyle[style][8];
TX[9] = LEDstyle[style][9];
TX[10] = LEDstyle[style][10];
SJASendData(TX); //将要发送的数据放到SJA1000的发送缓冲区
SJARegWrite(0x01, 0x10); //启动自发自收
}
//
//CAN接收处理函数
//
void CANRece(void)
{
unsigned char i;
unsigned char tempdata;
for (i=0; i<8; i++) //用四个LED循环显示接收到的八个数据(每个数据只用低四位)
{
tempdata = RX[i+3]; //循环读取SJA1000接收缓冲区里的8个数据字节
RS232Send(tempdata); //并将值发送到串口,可通过串口软件监控数据
tempdata |= 0xf0; //为了不改变键盘数值,加此句
P1 =tempdata; //送到LED灯显示
DelayTime(1000); //延时,让流水灯的花式可以观察得到
}
P1 = 0xff; //清除所有显示
}
//
//串口初始化
//
void RS232Init(void)
{
SCON = 0x50; //SCON: 串口工作方式1, 8位数据位,1位停止位
TMOD |= 0x20; //TMOD: 定时器1, 工作方式2, 8位自动重载
PCON |= 0x80; //SMOD=1;
TH1 = 0xFD; //SMOD=1,波特率:19200 晶振=110592MHz
//IE |= 0x90; //使能串口中断
TR1 = 1; //启动定时器1
}
//
//串口发送函数
//
void RS232Send(unsigned char tempdata)
{
SBUF =tempdata; //在显示的同时,也把数据往串口发送
while(!TI);
TI = 0;
}
//
//延时函数
//
void DelayTime (unsigned char times)
{
unsigned char i=0;
while(times--)
{
for(i=0;i<50;i++)
{;}
}
}
//
//结束
//

1) 如果需要,在IICADD寄存器内写入自己的从地址。
2) 设置IICCON寄存器:使能中断,定义SCL周期。
3) 设置IICSTAT来使能连续输出。
如果一个从设备接收者不能应答从地址的确认,它将会保持SDA行为高电平。在这种情况下,主设备会产生停止条件同时异常中断传输。
如果主设备接收者异常中断传输,它会在最后的数据字节接收完后通过取消ACK的产生标记从设备传输 *** 作的结束。从设备发送者会释放SDA来允许主设备产生停止信号
为了控制连续时钟(SCL)的频率,4位预分频器的值会在IICCON寄存里编辑。IIC总线接口地址存贮在IIC总线地址(IICADD)寄存器内。(在默认情况下,IIC总线地址为一个不可知值。)


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/13164127.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-06-14
下一篇 2023-06-14

发表评论

登录后才能评论

评论列表(0条)

保存