⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 main11.c

📁 一个基于SJA1000的CAN总线通讯程序
💻 C
字号:
#include <absacc.h>
#include <P89C58_PLUS.H>
#include "SJA1000.h"
#define MAX_AD_RECV_LEN		24
#define SLOT_ADDR			0xB000
#define SLOT_ADDR_COM  		0x02 // 定义基址

#define CAN_FLAG_NONE		0x00
#define CAN_FLAG_START		0x01
#define CAN_FLAG_RUNNING	0x02
#define CAN_FLAG_END		0x03

#define STA_IDLE			0
#define STA_RECEIVING		1
#define STA_SENDING			2

sbit    CAN0_RST = P3^4;
sbit    CAN1_RST = P1^0;
sbit    CS_LED = P1^3;
sbit    AD_CLK = P1^4;
sbit    AD_OUT = P1^5;
sbit    AD_IN  = P1^6;
sbit    AD_EOC = P3^3;
sbit    CS_AD  = P1^7;

sbit    TEST  =  P3^3;

unsigned char idata m_ad_buff[MAX_AD_RECV_LEN]; //高128位RAM7F-ff 指针方式
unsigned int  idata m_ad_tmp[5][11];
unsigned char m_times;

unsigned char bdata m_led_cond;//可位寻址的内存空间
sbit b_led1=m_led_cond^0;
sbit b_led2=m_led_cond^1;
sbit b_led3=m_led_cond^2;
sbit b_led4=m_led_cond^3;
sbit b_led5=m_led_cond^4;
sbit b_led6=m_led_cond^5;
sbit b_led7=m_led_cond^6;
sbit b_led8=m_led_cond^7;


unsigned char xdata *m_pByte;
unsigned int  m_last_time;
unsigned int  m_out_time;

unsigned char m_addr;
unsigned char m_chn_no;

// ...CAN 缓冲区....//
unsigned char m_CanSend[10];
unsigned char m_CanRecv[10];
bit      m_bAuto;

unsigned char m_can_msg_len;
unsigned char m_can_recvs;
unsigned char idata m_buffull;

void P89C58_init();
void SJA1000_init();
bit  SJA1000_Send();
void TLC2543C_init();

unsigned char GetCANAddr();

unsigned int GetCRC(unsigned char num,unsigned char *pData);
extern void _nop_ (void);

void delay(unsigned int num)
{
    unsigned int i;
    for (i = 0; i < num; i ++) {
        _nop_();
    }
}
//AD采样状态显示子程序//
void LightLed()
{
    unsigned char i;
    unsigned char tmp;    
    unsigned char led;
    unsigned int  m_ad_result;

    led = 0;	
    for(i=0;i<8;i++)
    { 	
        m_ad_result =  m_ad_buff[2*i]<<8;
	    m_ad_result += m_ad_buff[2*i+1];
	    tmp = m_led_cond&(0x01<<i);
	    if(tmp&&(m_ad_result < 630))
	    {
	        led = led & (~(0x01<<i));
	    }	
        else led = led | (0x01<<i);
    }
    EA = 0;		
    P0 = led;
    CS_LED = 1; 
    CS_LED = 0; 
    EA = 1;
}

// ..得到CRC校验数据//
unsigned int GetCRC(unsigned char num,unsigned char *pData)
{
    unsigned char i,j;
	unsigned int  m_CRC;

    m_CRC = 0xffff;
    for( i = 0; i < num; i ++)
    {
      m_CRC = m_CRC^(*(pData + i));
      for( j = 0; j < 8; j++ )
	  {
	    if(m_CRC & 0x01)
	    {
		   m_CRC = m_CRC >> 1;
		   m_CRC=m_CRC ^ 0xa001;
	    }
	    else
	    {
		   m_CRC = m_CRC >> 1;
	    }
	  }
    }
	return m_CRC;    
}

/***************************************************************************************************************************************
 ..........................................P89C58.............................
 **************************************************************************************************************************************/
void P89C58_init()
{    
    TMOD = 0x21; //Mode 2: 自动复位
    RCAP2H = 0xFF;
    RCAP2L = 0xB2;
    CS_LED = 0; //disable 573
    TH0 = 0xF8; //...1mS 中断
	TL0 = 0x30;

    // ...开中断//
    IE = 0;
    ET0 = 1; //T0中断使能
    EX0 = 1; // 为 SJA1000 INT使能 INT0
    EX1 = 0; //关闭 AD INT 的INT1
    ES  = 0; //关闭串口中断.

    // ...启动定时器 2
    TR0 = 1;   
}


/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 * Function:P89C58_ISR_Timer0()
 * Description:
 *	 Timer0 中断服务子程序
 */
void P89C58_ISR_Timer0() interrupt 1 using 2
{
   m_last_time = m_last_time ++;
   if(m_last_time > 3000) m_last_time = 3000;
   TH0 = 0xF8; //...1mS interrupt
   TL0 = 0x30;
   TR0 = 1;
}

/***************************************************************************************************************************************
 ..........................................SJA1000.............................
 **************************************************************************************************************************************/
void SJA1000_init()
{
   int j;

   CAN0_RST = 0;/*硬件复位SJA1000	,拉低RST引脚*/
   for(j = 0; j < 1000; j ++)
   {
      _nop_();			/*持续一段时间*/
   }
   CAN0_RST = 1;/*释放,硬件复位结束*/

  
   SJA_REG_CR = 0x01; // 进入复位模式

   SJA_REG_ACR = m_addr;/*接收码为本程采集单元地址*/
   SJA_REG_AMR = 0x03; /* 0000 00XX 接收屏蔽码,1、2不相关*/

   SJA_REG_BTR0 = 0x00;/*总线定时器0缺省*/
   SJA_REG_BTR1 = 0x14;/*总线定时器1,24Mhz晶振,9.6kb/s*/
   SJA_REG_OCR = 0xAA;/*输出控制寄存器,正常输出模式,TX0正逻辑、下拉输出驱动*/
   SJA_REG_CDR = 0x48;/*can模式为basicCAN模式,CLKOUT关闭,允许外接发送接收电路*/

   // 进入工作模式
   SJA_REG_CR = 0x1A; /*允许溢出、出错、接收中断,但不发送数据 */  
  }
/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 * Function:
 * Description:
 *	 CAN 中断服务子程序
 */
void SJA1000_ISR_0() interrupt 0 using 1
{
    unsigned char i;
    unsigned char num;
    unsigned char dlc;
    unsigned char status;
    unsigned char iir;	

    iir = SJA_REG_IR;
    status = SJA_REG_SR;

    if (iir & 0x01) {//接收中断
        m_CanRecv[0] = SJA_REG_RxBuf0;
	m_CanRecv[1] = SJA_REG_RxBuf1;
        dlc = m_CanRecv[1] & 0x0F;
	    for ( i = 0; i < dlc; i ++){
	        m_pByte = SJA_REG + 0x16 + i; //  接收数据送入缓冲区
	        num = *m_pByte;
	        m_CanRecv[i + 2] = num;
	    }
            m_can_msg_len=dlc-1;
	    m_buffull = 0x55;
            SJA_REG_CMD = 0x04; /*命令寄存器  RRB=1 释放SJA1000接收缓存*/  
    }

    if (iir & 0x08) {//数据溢出中断
	    SJA_REG_CMD = 0x08; // CDO=1 清除数据溢出
    }
 }

/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 * Function:SJA1000_Send()
 * Description:
 *	 SJA1000 发送数据
 */
bit SJA1000_Send()
{
    unsigned char i;
    unsigned char num;
    unsigned char status;
    
    status = SJA_REG_SR;

    if (status & 0x04 == 0) return 0;/*状态,判断上次发送完成且发送缓存已释放*/
	if (status & 0x08 == 0) return 0;

	for ( i = 0; i < 200; i ++) {
	   _nop_();
	}

    num = m_CanSend[1] & 0x0F;
    num = num + 2;
    for ( i = 0; i < num; i ++)//写入发送缓存
    {
       m_pByte = SJA_REG + 0x0A + i; // 0x0A: 发送缓存区偏移地址
       *m_pByte = m_CanSend[i];
    }
    SJA_REG_CMD = 0x01; //  TR=1 置发送请求
    return 1;
}

/***************************************************************************************************************************************
 ..........................................AD Converter(TLC2543C).............................
 ADDRESS BITS 		L1 L0 LSBF 	BIP
 D7	D6 D5 D4 		D3 D2 D1   	D0
(MSB)							(LSB)
 **************************************************************************************************************************************/
//AD 初始化子程序//
void TLC2543C_init()
{
    unsigned char i;
   
    AD_CLK = 0;
    CS_AD = 0;
   
    for (i = 0; i < 22; i ++) m_ad_buff[i] = 0;   
    delay(5);
   
}
//AD数据处理子程序//
void TLC2543C_filter()
{  
    unsigned char i;
	unsigned char j;
	unsigned int max;
	unsigned int min;
	unsigned int sum;    
	
    for (i=0;i<11;i++)
	{
	    max = m_ad_tmp[0][i];
		min = m_ad_tmp[0][i];
		
        for(j=1;j<5;j++)                //得到最大值和最小值
		{
            if(m_ad_tmp[j][i] > max) max = m_ad_tmp[j][i];
			else if(m_ad_tmp[j][i] < min) min = m_ad_tmp[j][i];			
		}

		sum = 0;                       //计算5个值的总和
		for(j=0;j<5;j++)
		{
		    sum += m_ad_tmp[j][i];								
		}

		sum = sum - max;               //减去最大值和最小值
		sum = sum - min;
		sum = sum / 3;

		m_ad_buff[2*i]   = sum >> 8;   //得到处理结果
		m_ad_buff[2*i+1] = sum;
	}
   
}
//AD采样子程序//
unsigned int TLC2543C_ad(unsigned char channel)
{    
    unsigned char chn;
	  unsigned char i;
    unsigned int  val;    

	chn = channel<<4; /*0xB0----(Vref+ - Vref-)/2   0xC0---Vref-   0xD0---Vref+*/	
	val = 0;//差动
    
	AD_CLK = 0;
	CS_AD = 0;	
    delay(10);    

	for (i = 0; i < 12; i ++) {
        if (chn & 0x80) AD_IN = 1;
		else AD_IN = 0;
		chn <<= 1;
		delay(10);	
		AD_CLK = 1; 
        val = val << 1;
		if (AD_OUT) val ++;			
		delay(10);
		AD_CLK = 0;		
	}		
	
	delay(10);
	CS_AD = 1;
	return val;	
}
//CAN 总线地址//
unsigned char GetCANAddr() {
    unsigned char tmp_addr;
    m_pByte = SLOT_ADDR;
    tmp_addr = *m_pByte;
    tmp_addr = tmp_addr & 0x0F;
    tmp_addr = tmp_addr - SLOT_ADDR_COM;
    tmp_addr = tmp_addr*4; 

	return tmp_addr;
}

// ...CAN 总线数据传输//
void UploadData()
{    
       m_CanSend[0] = m_addr;
	   m_CanSend[1] = 0x08;
	   m_CanSend[2] = CAN_FLAG_START;
	   m_CanSend[3] = m_ad_buff[0]; //chn0
	   m_CanSend[4] = m_ad_buff[1];
	   m_CanSend[5] = m_ad_buff[2]; //chn1
	   m_CanSend[6] = m_ad_buff[3];
	   m_CanSend[7] = m_ad_buff[4]; //chn2
	   m_CanSend[8] = m_ad_buff[5];
	   m_CanSend[9] = m_ad_buff[6]; //chn3
	   while(!SJA1000_Send());
	   
       m_CanSend[0] = m_addr;
	   m_CanSend[1] = 0x08;
	   m_CanSend[2] = CAN_FLAG_RUNNING;
	   m_CanSend[3] = m_ad_buff[7];
	   m_CanSend[4] = m_ad_buff[8];  //chn4
	   m_CanSend[5] = m_ad_buff[9];
	   m_CanSend[6] = m_ad_buff[10]; //chn5
	   m_CanSend[7] = m_ad_buff[11];
	   m_CanSend[8] = m_ad_buff[12]; //chn6
	   m_CanSend[9] = m_ad_buff[13];	  
	   while(!SJA1000_Send());	   
       
	   m_CanSend[0] = m_addr;
	   m_CanSend[1] = 0x08;
	   m_CanSend[2] = CAN_FLAG_RUNNING;
	   m_CanSend[3] = m_ad_buff[14]; //chn7//
	   m_CanSend[4] = m_ad_buff[15];
	   m_CanSend[5] = m_ad_buff[16]; //chn8//
	   m_CanSend[6] = m_ad_buff[17];
	   m_CanSend[7] = m_ad_buff[18]; //chn9//
	   m_CanSend[8] = m_ad_buff[19];
	   m_CanSend[9] = m_ad_buff[20]; //chn10//	   
	   while(!SJA1000_Send());
	   
       m_CanSend[0] = m_addr;
	   m_CanSend[1] = 0x04;
	   m_CanSend[2] = CAN_FLAG_END;;
	   m_CanSend[3] = m_ad_buff[21];
	   m_CanSend[4] = m_ad_buff[22];
	   m_CanSend[5] = m_ad_buff[23]; //sum	      
	   while(!SJA1000_Send());
}

//...串口传输协议....//
void STProtocol()
{
     unsigned char fun; 
   	 unsigned int  timeout;
     bit bRet=1;

    fun = m_CanRecv[3];
	 
    if(m_buffull!=0x55) return;
    m_buffull=0;		 	 

    if (fun == 0x04 && m_can_msg_len == 4) //功能码:用来设置数据上传的时间间隔

    {// 设置检测延迟时间
	    timeout = m_CanRecv[5];
        timeout = timeout << 8;
        timeout = timeout + m_CanRecv[4];
        m_out_time = timeout;
		m_led_cond = m_CanRecv[6];
    }
    else if (fun == 0x06 && m_can_msg_len == 1) //0x06功能码:使数据采集板复位

    {// 复位    
	    while(1) {;} //等待看门狗
    }
    else if (fun == 0x07 && m_can_msg_len == 1) //0x07功能码:用来停止数据上传。

    {// 是否准备发送实时命令
        m_bAuto = 0;
    }
    else if (fun == 0x08 && m_can_msg_len == 1) //0x08功能码:用来启动数据上传

    {// 开始发送实时命令	 
        m_bAuto = 1;
    }
    else 
    {
	bRet = 0;
    }

    if (bRet) 
    {	  
      m_CanSend[0] = m_addr;
	    m_CanSend[1] = 0x03;
      m_CanSend[2] = CAN_FLAG_END;
	    m_CanSend[3] = fun;
	    m_CanSend[4] = 0;
	    while(!SJA1000_Send());
    }
}

void main(void)
{    
    unsigned char i;
    unsigned int value;

    EA = 0;

    m_addr = GetCANAddr();
    P89C58_init();
    SJA1000_init();
    TLC2543C_init();

    m_out_time = 200;
    m_can_recvs = 0;    
    m_can_msg_len=0;
    m_led_cond = 0x00;       //电流环断线时指示灯灭	
    m_bAuto = 0;
    EA = 1;

    while(1) 
    {
        kickdog;//喂狗
	          
        STProtocol();	   
 	    m_times ++;
    	if(m_times > 4) m_times = 0; 	   
    	for(i=0;i<11;i++)                        //得到AD采样值,大约22MS
	    {
	        if(i==10)  m_ad_tmp[m_times][i] = TLC2543C_ad(0);        
            else m_ad_tmp[m_times][i] = TLC2543C_ad(i+1);
    	} 
	   
 	    TLC2543C_filter();										//AD数据处理
        LightLed();                              //显示AD采样对应在显示面板上的状态
  	   
        if (!m_bAuto) continue;              //不更新数据	
   	    if (m_last_time < m_out_time) continue;  //时间没有到,数据暂时不需更新
	    m_last_time = 0;	 

	    m_addr = GetCANAddr();
    	value = GetCRC(22, m_ad_buff);          //CRC校验
    	m_ad_buff[22]=value;
     	m_ad_buff[23]=value>>8;   
  	    UploadData();                           //更新AD数据
    }
}// end main

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -