找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 216|回复: 2
打印 上一主题 下一主题
收起左侧

CAN通讯MCP2515模块 标准帧例程 STC15单片机

[复制链接]
跳转到指定楼层
楼主
ID:63317 发表于 2024-4-9 07:08 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
买的不会玩大家研究研究
怎样能实现和车通讯
/*********************************************************************************/
/*注意:本例程是基于STC15系列最新增强型51单片机编写,由于不同系列51单片机一些外设*/
/*功能配置存在差异,请亲们在使用时对应进行修改。*/
/*********************************************************************************/


#include "STC15F2Kxx.h"
#include "MCP2515.H"


#define FOSC 11059200L                        //系统频率
#define T1MS (65536-FOSC/1000)        //定时器工作在1T模式下定时1ms的计数器值(写入THx、TLx的值)
#define BAUD 9600                                //串口1波特率
#define UART1_Rx_Buff_LEN 100        //串口1数据缓冲区数据长度


bit busy=0;                                                                                        //串口1发送数据忙标志位
unsigned char UART1_Rx_Buffer[UART1_Rx_Buff_LEN];        //串口1接收保存缓冲区
unsigned char Uart1_Delay=0;                                                //串口1接收数据帧延时(ms),延时时间到当1帧数据接收完成
unsigned char Uart1_Write_Count=0;                                        //写串口1缓冲区指针
unsigned char Uart1_Read_Count=0;                                        //读串口1缓冲区指针
unsigned char Uart1_Finish=0;                                                //当前一帧数据接收完成标志


unsigned char CAN_Flag=0;                                                        //CAN接收到数据标志
unsigned char CAN_R_Buffer[8];                                                //CAN接收数据保存缓冲区


/*******************************************************************************
* 函数名  : Timer0_Init
* 描述    : 定时器0初始化配置
* 输入    : 无
* 输出    : 无
* 返回值  : 无
* 说明    : 无
*******************************************************************************/
void Timer0_Init(void)
{
    AUXR |= 0x80;                //定时器0为1T模式
    TMOD = 0x00;                //设置定时器为模式0(16位自动重装载)
    TL0 = T1MS;                        //初始化计时值
    TH0 = T1MS >> 8;
    TR0 = 1;                        //定时器0开始计时
    ET0 = 1;                        //使能定时器0中断
    EA = 1;                                //使能总中断                                                        
}


/*******************************************************************************
* 函数名  : Timer0_ISR
* 描述    : 定时器0中断服务函数
* 输入    : 无
* 输出    : 无
* 返回值  : 无
* 说明    : 本程序用于检测1帧串口数据接收完成
*******************************************************************************/
void Timer0_ISR() interrupt 1 using 1
{
        if(Uart1_Delay>0)
        {
                Uart1_Delay--;
                if(Uart1_Delay==0)
                {
                        //延时时间到再没有接收到新的串口数据,表示1帧数据接收完成
                        if(Uart1_Write_Count != Uart1_Read_Count) Uart1_Finish=1;
                }
        }
}


/*******************************************************************************
* 函数名  : Exint1_Init
* 描述    : 外部中断1初始化函数
* 输入    : 无
* 输出    : 无
* 返回值  : 无
* 说明    : 无
*******************************************************************************/
void Exint1_Init(void)
{
    PX1=1;                //设置外部中断1的中断优先级为高优先级
    IT1 = 1;        //设置INT1的中断类型 (1:仅下降沿 0:上升沿和下降沿)
    EX1 = 1;        //使能INT1中断
    EA = 1;         //使能总中断
}




/*******************************************************************************
* 函数名  : Exint1_ISR
* 描述    : 外部中断1中断服务函数
* 输入    : 无
* 输出    : 无
* 返回值  : 无
* 说明    : 用于检测MCP2515中断引脚的中断信号
*******************************************************************************/
void Exint1_ISR(void) interrupt 2 using 1
{
        CAN_Flag=1;//CAN接收到数据标志
}


/*******************************************************************************
* 函数名  : UART1_Init_Config
* 描述    : UART1初始化配置
* 输入    : 无
* 输出    : 无
* 返回值  : 无
* 说明    : 无
*******************************************************************************/
void UART1_Init_Config(void)
{
    P_SW1 &= 0x3f;                                        //设置串口1在(P3.0/RxD, P3.1/TxD)
    SCON = 0x50;                                        //8位UART,可变波特率,允许串行接收
        AUXR &= 0xfe;                                        //定时器1为1T模式        
    AUXR |= 0x40;                                        //定时器1为1T模式
        TMOD &= 0xF0;                                        //定时器1为模式0(16位自动重载)
    TL1 = (65536 - (FOSC/4/BAUD));        //设置波特率重装值的低8位
    TH1 = (65536 - (FOSC/4/BAUD))>>8;//设置波特率重装值的高8位
    TR1 = 1;                                                //启动定时器1计数
    ES = 1;                                                        //使能串口中断
    EA = 1;                                                        //使能总中断
}


/*******************************************************************************
* 函数名  : UART1_Buffer_PntAdd
* 描述    : 读、写串口1缓冲区指针加1
* 输入    : *pnt(指向串口1读、写串口1缓冲区指针)
* 输出    : 无
* 返回值  : 无
* 说明    : 无
*******************************************************************************/
void UART1_Buffer_PntAdd(unsigned char *pnt)
{
        *pnt+=1;
        if(*pnt >= UART1_Rx_Buff_LEN) *pnt=0;
}


/*******************************************************************************
* 函数名  : UART1_ISR
* 描述    : UART1中断服务函数
* 输入    : 无
* 输出    : 无
* 返回值  : 无
* 说明    : 无
*******************************************************************************/
void UART1_ISR(void) interrupt 4 using 1
{
        unsigned char ch;
        //接收数据
        if(RI)
        {
                RI = 0;//清除RI位
                ch=SBUF;
                UART1_Rx_Buffer[Uart1_Write_Count]=ch;        //将接收到的数据写入缓冲区
                UART1_Buffer_PntAdd(&Uart1_Write_Count);//写串口1缓冲区指针加1                        
                if(Uart1_Write_Count == Uart1_Read_Count)//如果读、写缓冲区指针重叠,则读指针加1,这时将丢失1个字节数据
                {
                        UART1_Buffer_PntAdd(&Uart1_Read_Count);//读串口1缓冲区指针加1
                }
                Uart1_Delay = 20;//串口1接收数据帧延时(ms),延时时间到当1帧数据接收完成
        }
        //发送数据
        if (TI)                        
        {
                TI = 0;                //清除TI位
                busy = 0;        //清忙标志(1忙,0空闲)
        }
}


/*******************************************************************************
* 函数名  : UART1_SendData
* 描述    : UART1发送一个字节
* 输入    : dat:待发送数据
* 输出    : 无
* 返回值  : 无
* 说明    : 无
*******************************************************************************/
void UART1_SendData(unsigned char dat)
{
    while (busy);        //等待前面的数据发送完成
    busy = 1;                //串口1发送数据忙标志位(1忙,0空闲)
    SBUF = dat;                //写数据到UART数据寄存器
}


/*******************************************************************************
* 函数名  : UART1_SendBuffer
* 描述    : UART1发送一个缓冲区数据
* 输入    : *buff:待发送缓冲区首地址,len:待发送数据长度
* 输出    : 无
* 返回值  : 无
* 说明    : 无
*******************************************************************************/
void UART1_SendBuffer(unsigned char *buff,unsigned int len)
{
        unsigned int i=0;


        if(len<=0) return;


        do
        {
                UART1_SendData(buff[i++]);//发送当前字符
        }while(i<len);
}


/*******************************************************************************
* 函数名  : CAN_Send_Dispose
* 描述    : CAN发送串口1接收到的数据处理函数
* 输入    : 无
* 输出    : 无
* 返回值  : 无
* 说明    : 无
*******************************************************************************/
void CAN_Send_Dispose(void)
{
        unsigned char i=0,len=0,write=0,buff[8];
        
        write = Uart1_Write_Count;
        if(Uart1_Write_Count<Uart1_Read_Count) write+=UART1_Rx_Buff_LEN;
        
        if((write-Uart1_Read_Count) >= 8)//如果串口1接收缓冲区中未读数据大于8个字节,则通过CAN总线发送8个字节数据(CAN发送一帧报文最大8个字节)
        {                        
                len = 8;                                                        
        }
        else if(Uart1_Finish == 1)//如果串口1接收缓冲区中未读数据小于8个字节,且再也没接收到串口的数据,则CAN发送剩余的数据
        {
                len = write-Uart1_Read_Count;
                Uart1_Finish=0;//当前一帧数据接收完成标志                        
        }
        else return;//如果串口1接收缓冲区中未读数据小于8个字节,且还在接收串口的数据则CAN先不发数据,等够8个字节了再发


        for(i=0;i<len;i++)
        {
                buff[ i] = UART1_Rx_Buffer[Uart1_Read_Count];//将串口接收缓冲区的数据复制到CAN发送临时缓冲区buff[ i]
                UART1_Buffer_PntAdd(&Uart1_Read_Count);//读串口1缓冲区指针加1
        }        
        CAN_Send_Buffer(buff,len);//CAN发送指定长度的数据
}


/*******************************************************************************
* 函数名  : main
* 描述    : 主函数,用户程序从main函数开始运行
* 输入    : 无
* 输出    : 无
* 返回值  : 无
* 说明    : 无
*******************************************************************************/
void main(void)
{
        Timer0_Init();                        //定时器0初始化配置
        UART1_Init_Config();        //UART1初始化配置
        Exint1_Init();                        //外部中断1初始化函数
        MCP2515_Init();                        //MCP2515初始化配置
                                
        while(1)
        {
                if(Uart1_Write_Count != Uart1_Read_Count)//如果读指针不等写指针,则证明串口1接收到数据
                {
                        CAN_Send_Dispose();//CAN发送串口1接收到的数据处理函数
                }
                else if(Uart1_Finish == 1) Uart1_Finish = 0;
               
                while((CAN_Flag==1) || ((P3&0x08) == 0))        
                {
                        unsigned char len;
                        
                        CAN_Flag=0;//CAN接收到数据标志        
                        len = CAN_Receive_Buffer(CAN_R_Buffer);//CAN接收一帧数据
                        if(len != 0)                                       
                        UART1_SendBuffer(CAN_R_Buffer,len);//UART1发送一个缓冲区数据
                }        
        }
}


原理图: 无
仿真: 无
代码: CAN通讯MCP2515模块-标准帧例程(STC15).rar (70.91 KB, 下载次数: 9)
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏1 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:961114 发表于 2024-4-10 16:40 | 只看该作者
你这个不吱声的  咋不用32G8K48,两个can,才一块多
回复

使用道具 举报

板凳
ID:433219 发表于 2024-4-12 21:38 | 只看该作者
STC庄伟 发表于 2024-4-10 16:40
你这个不吱声的  咋不用32G8K48,两个can,才一块多

是啊   MCP2515 光芯片就卖5~25元,简直杀猪价  
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表