STM32F103VET6的CAN通信代码分享

STM32F103VET6的CAN通信代码分享

STM32F103VET6单片机之间的CAN通信+筛选器配置(白名单模式)。

CAN_Filter_0 : 16位列表模式,配置4个标准帧ID;
CAN_Filter_1 : 32位列表模式,配置2个扩展帧ID;
CAN_Filter_2 : 32位列表模式,配置2个扩展帧ID;
其它10个筛选器未使用。

参考的资料

  1. 《零死角玩转STM32—F429.pdf》,可以去野火电子论坛下载
  2. STM32标准库官方demo《STM32F10x_StdPeriph_Lib_V3.5.0.rar》,可以去st.com直接搜索“STSW-STM32054”或者复制以下链接访问,前提是要注册一个账号才能下载
    https://www.st.com/content/st_com/en/products/embedded-software/mcu-mpu-embedded-software/stm32-embedded-software/stm32-standard-peripheral-libraries/stsw-stm32054.html

说明

CAN的相关介绍,请自行查找资料,本次分享不做介绍;请自行阅读上述参考的资料相关内容,个人认为讲解的比较全面。

CAN通信须满足的条件

  1. 硬件没问题
  2. 且两块板子断电后,CAH-HCAN-L总线之间的阻值须保证在60欧母左右;
  3. 其次两个单片机的CAN外设必须配置正确,一旦有一个单片机的CAN没有配置,就不会通信正常。

代码的主要功能

  1. 单片机A单片机B的代码完全一样,都是间隔500ms发送一帧数据,数据有8帧标准帧和8帧扩展帧;且发送成功后,运行灯会亮50ms;
  2. CAN接收中断服务函数内,先判断接收数据属于标准帧还是扩展帧,接着通过串口打印接收数据桢的ID;
  3. printf函数映射到串口3;
  4. 控制运行灯的GPIO为PB11低电平点亮LED;
  5. 以上3、4可以根据实际情况自行更改;

代码

博客设置页面,选择一款你喜欢的代码片高亮样式,下面展示同样高亮的 代码片.

// An highlighted block
#include "stm32f10x_conf.h"
#include "stdio.h"

#define RUN_LED_ON          GPIOB->BRR = GPIO_Pin_11
#define RUN_LED_OFF         GPIOB->BSRR = GPIO_Pin_11

const uint32_t ul_CAN_ID_table[16] = {  0x100,
                                        0x101,
                                        0x102,
                                        0x103,
                                        0x104,
                                        0x105,
                                        0x106,
                                        0x107,
                                        0x18880000,
                                        0x18880001,
                                        0x18880002,
                                        0x18880003,
                                        0x18880004,
                                        0x18880005,
                                        0x18880006,
                                        0x18880007};

uint8_t uc_temp_table[8];
                                        
void systick_config(void)
{
    SysTick->CTRL &= SysTick_CLKSource_HCLK_Div8;
    SysTick->CTRL &= ~SysTick_CTRL_TICKINT_Msk;
}

void SysTick_Delay_ms(uint32_t ticks)//16777215    16777215 / 9000 = 1864.135
{
    if(ticks > 1864)
        ticks = 1864;            
    SysTick->LOAD  = ticks * 9000 - 1;                  /* set reload register */    
    SysTick->VAL   = 0;                                 /* Load the SysTick Counter Value */    
    SysTick->CTRL  |= SysTick_CTRL_ENABLE_Msk;          /* Enable SysTick Timer down counter */
    do
    {
        ticks = SysTick->CTRL;
    }
    while((ticks & 0x01)&&!(ticks & SysTick_CTRL_COUNTFLAG_Msk));
    
    SysTick->CTRL  &= ~SysTick_CTRL_ENABLE_Msk;         /* Stop the SysTick Timer(counter disabled) */    
    SysTick->VAL   = 0;
}

void gpio_config(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;

    /* GPIOD Periph clock enable */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    
    /* Configure output pushpull mode */
    /* PB11 RUN_LED */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_Init(GPIOB, &GPIO_InitStructure);
}

/*
pin55   PD8     FSMC_D13        USART3_TX(remap)
pin56   PD9     FSMC_D14        USART3_RX(remap)
*/
void USART3_config(void)
{
    USART_InitTypeDef USART_InitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);    
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
    
    /* Configure USARTy Rx as input floating */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOD, &GPIO_InitStructure); 

    /* Configure USARTy Tx as alternate function push-pull */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOD, &GPIO_InitStructure);

    GPIO_PinRemapConfig(GPIO_FullRemap_USART3, ENABLE);
    
    USART_InitStructure.USART_BaudRate = 115200;
    USART_InitStructure.USART_BaudRate = 2000000;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    USART_Init(USART3,&USART_InitStructure);
    
    USART_Cmd(USART3,ENABLE);
}

void USARTx_Send_Single_Byte(USART_TypeDef* USARTx,uint8_t Temp_data)
{
    USART_ClearFlag(USARTx,USART_FLAG_TC);
    USART_SendData(USARTx,Temp_data);
    while(USART_GetFlagStatus(USARTx,USART_FLAG_TC)==RESET);
}

/* 
功能:can1配置
500kbps,其它波特率下面有介绍

筛选器用了0、1、2,三个都配置为白名单模式,未使用掩码模式,只接收白名单的帧
筛选器0:16位白名单模式,配置了4个白名单标准帧ID
筛选器1:32位白名单模式,配置了2个白名单扩展帧ID
筛选器2:32位白名单模式,配置了2个白名单扩展帧ID

CAN1有两个接收FIFO(FIFO0 和 FIFO1),本程序只使用了FIFO0;三个筛选器都映射到FIFO0

程序最前面定义了16个ID,其中8个标准帧ID,8个扩展帧ID
*/
void can_config(void)
{
    GPIO_InitTypeDef  GPIO_InitStructure;
    CAN_InitTypeDef        CAN_InitStructure;
    CAN_FilterInitTypeDef  CAN_FilterInitStructure;
    NVIC_InitTypeDef  NVIC_InitStructure;
    
    NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 5;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    /* Configure CAN1 IOs **********************************************/
    /* GPIOD and AFIO clocks enable */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOD, ENABLE);
    /* CAN1 Periph clocks enable */
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);

    /* Configure CAN1 RX pin */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_Init(GPIOD, &GPIO_InitStructure);

    /* Configure CAN1 TX pin */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOD, &GPIO_InitStructure);

    /* Remap CAN1 GPIOs */
    GPIO_PinRemapConfig(GPIO_Remap2_CAN1 , ENABLE);

    /* Configure CAN1 **************************************************/  
    /* CAN1 register init */
    CAN_DeInit(CAN1);
    /* Struct init*/
    CAN_StructInit(&CAN_InitStructure);
    
    /* CAN1 cell init */
    CAN_InitStructure.CAN_TTCM = DISABLE;
    CAN_InitStructure.CAN_ABOM = DISABLE;
    CAN_InitStructure.CAN_AWUM = DISABLE;
    CAN_InitStructure.CAN_NART = DISABLE;
    CAN_InitStructure.CAN_RFLM = DISABLE;
    CAN_InitStructure.CAN_TXFP = ENABLE;    
    CAN_InitStructure.CAN_Mode = CAN_Mode_Normal;
    CAN_InitStructure.CAN_SJW = CAN_SJW_1tq;//reSynchronization Jump Width
    CAN_InitStructure.CAN_BS1 = CAN_BS1_3tq;
    CAN_InitStructure.CAN_BS2 = CAN_BS2_2tq;
    
    /*CLK_APB1 = 36MHz
    ss = 1      bs1 = 3     bs2 = 2
    bit time width is 6(1 + 3 + 2)
    baudrate period is tq*6
    
    36MHz / 6 = 6MHz

    6MHz / CAN_Prescaler
    = 6MHz / 12
    = 500KHz
    */
    
    /*
    1 Tq = 1/(36MHz / CAN_Prescaler)
         = 1/3 us
    T1bit = (1 + 3 + 2) * Tq = 2us
    baudrate = 1/T1bit = 500Kbps
    */
    //这里选择波特率
    /* CAN_Prescaler        bsp
            6               1MBps
            12              500KBps
            24              250KBps
            48              125KBps
            60              100KBps
            120             50KBps
            300             20KBps
            600             10KBps */    
    CAN_InitStructure.CAN_Prescaler = 12;
    /*Initializes the CAN1 */
    CAN_Init(CAN1, &CAN_InitStructure);
    
    /* CAN1 filter init */
    /* 16位白名单模式,4个标准ID */
    CAN_FilterInitStructure.CAN_FilterNumber = 0;
    CAN_FilterInitStructure.CAN_FilterMode              = CAN_FilterMode_IdList;
    CAN_FilterInitStructure.CAN_FilterScale             = CAN_FilterScale_16bit;
    CAN_FilterInitStructure.CAN_FilterIdHigh            = ((((uint32_t)0x100<<21)|CAN_ID_STD|CAN_RTR_DATA)&0xFFFF0000)>>16;
    CAN_FilterInitStructure.CAN_FilterIdLow             = ((((uint32_t)0x101<<21)|CAN_ID_STD|CAN_RTR_DATA)&0xFFFF0000)>>16;
    CAN_FilterInitStructure.CAN_FilterMaskIdHigh        = ((((uint32_t)0x102<<21)|CAN_ID_STD|CAN_RTR_DATA)&0xFFFF0000)>>16;
    CAN_FilterInitStructure.CAN_FilterMaskIdLow         = ((((uint32_t)0x103<<21)|CAN_ID_STD|CAN_RTR_DATA)&0xFFFF0000)>>16;
    CAN_FilterInitStructure.CAN_FilterFIFOAssignment    = CAN_Filter_FIFO0;//映射到FIFO0
    CAN_FilterInitStructure.CAN_FilterActivation        = ENABLE;
    CAN_FilterInit(&CAN_FilterInitStructure);
    
    /* CAN1 filter init */
    /* 32位白名单模式,2个扩展ID */
    CAN_FilterInitStructure.CAN_FilterNumber = 1;
    CAN_FilterInitStructure.CAN_FilterMode              = CAN_FilterMode_IdList;
    CAN_FilterInitStructure.CAN_FilterScale             = CAN_FilterScale_32bit;
    CAN_FilterInitStructure.CAN_FilterIdHigh            = ((((uint32_t)0x18880000<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF0000)>>16;
    CAN_FilterInitStructure.CAN_FilterIdLow             =  (((uint32_t)0x18880000<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0x0000FFFF;
    CAN_FilterInitStructure.CAN_FilterMaskIdHigh        = ((((uint32_t)0x18880001<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF0000)>>16;
    CAN_FilterInitStructure.CAN_FilterMaskIdLow         =  (((uint32_t)0x18880001<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0x0000FFFF;
    CAN_FilterInitStructure.CAN_FilterFIFOAssignment    = CAN_Filter_FIFO0;//映射到FIFO0
    CAN_FilterInitStructure.CAN_FilterActivation        = ENABLE;
    CAN_FilterInit(&CAN_FilterInitStructure);
    
    /* CAN1 filter init */
    /* 32位白名单模式,2个扩展ID */
    CAN_FilterInitStructure.CAN_FilterNumber = 2;
    CAN_FilterInitStructure.CAN_FilterMode              = CAN_FilterMode_IdList;
    CAN_FilterInitStructure.CAN_FilterScale             = CAN_FilterScale_32bit;
    CAN_FilterInitStructure.CAN_FilterIdHigh            = ((((uint32_t)0x18880002<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF0000)>>16;
    CAN_FilterInitStructure.CAN_FilterIdLow             =  (((uint32_t)0x18880002<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0x0000FFFF;
    CAN_FilterInitStructure.CAN_FilterMaskIdHigh        = ((((uint32_t)0x18880003<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF0000)>>16;
    CAN_FilterInitStructure.CAN_FilterMaskIdLow         =  (((uint32_t)0x18880003<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0x0000FFFF;
    CAN_FilterInitStructure.CAN_FilterFIFOAssignment    = CAN_Filter_FIFO0;//映射到FIFO0
    CAN_FilterInitStructure.CAN_FilterActivation        = ENABLE;
    CAN_FilterInit(&CAN_FilterInitStructure);

    /* IT Configuration for CAN1 */
    CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE);/*!< FIFO 0 message pending Interrupt*/
}

/*
功能:can 发送函数
参数:
ul_id_type:     CAN_Id_Standard 或者 CAN_Id_Extended
ul_id_data:     帧ID
*p_data:        数据指针
uc_temp_len:    要发送的数据长度,不大于8

注意:此函数会先后依次判断Mailbox(0、1、2)哪个处于空闲状态,并返回当前发送Mailbox的序号0、1、2
    若都不空闲,则返回100
*/
uint8_t sys_can_transmit_message(uint32_t ul_id_type,uint32_t ul_id_data,uint8_t *p_data, uint8_t uc_temp_len)
{
    uint8_t i = 0;
    uint8_t uc_TransmitMailbox = 100;
    CanTxMsg CanTxMsg_structure;
    
    assert_param(IS_CAN_IDTYPE(ul_id_type));
    
    if(uc_temp_len > 8)
        uc_temp_len = 8;
    
    if(ul_id_type == CAN_Id_Standard)
    {
        CanTxMsg_structure.IDE = CAN_ID_STD;
        CanTxMsg_structure.StdId = ul_id_data;
    }
    else
    {
        CanTxMsg_structure.IDE = CAN_ID_EXT;
        CanTxMsg_structure.ExtId = ul_id_data;
    }

    CanTxMsg_structure.RTR = CAN_RTR_DATA;
    CanTxMsg_structure.DLC = uc_temp_len;//data len
    
    for(i = 0;i < uc_temp_len;i++)
    {
        CanTxMsg_structure.Data[i] = p_data[i];
    }
    
    //判断三个Mailbox是否有处于空闲状态的
    if(CAN1->TSR&0x1C000000)//等效于   if(CAN1->TSR&(CAN_TSR_TME0 | CAN_TSR_TME1 | CAN_TSR_TME2)),参考 CAN_Transmit 的函数体定义
    {
        uc_TransmitMailbox = CAN_Transmit(CAN1, &CanTxMsg_structure);//CAN_Transmit也会判断哪个
    }
    
    return uc_TransmitMailbox;
}

int main(void)
{
    uint8_t i = 0;
    uint8_t j = 0;
    uint8_t uc_TransmitMailbox = 100;
    
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
    systick_config();
    gpio_config();
    USART3_config();
    can_config();
    
    RUN_LED_OFF;
    printf("system power on!!!\r\n");
    
    for(i = 0;i < 8;i++)
        uc_temp_table[i] = i;
    
    /* Infinite loop */
	while(1)
    {
        for(j = 0;j < 16;j++)
        {
            SysTick_Delay_ms(500);
            if(j < 8)//前8帧数据为标准帧
                uc_TransmitMailbox = sys_can_transmit_message(CAN_Id_Standard,ul_CAN_ID_table[j],uc_temp_table,8);
            else//后8帧数据为扩展帧
                uc_TransmitMailbox = sys_can_transmit_message(CAN_Id_Extended,ul_CAN_ID_table[j],uc_temp_table,8);
            
            //CAN1 共有3个发送Mailbox(0 1 2),sys_can_transmit_message函数返回的是发送的邮箱号
            //当邮箱号为 0 、1、2时,表示发送成功
            if(uc_TransmitMailbox < 3)
            {
                RUN_LED_ON;
                SysTick_Delay_ms(50);
                RUN_LED_OFF;
            }
        }
	}
}
/* CAN 接收中断处理函数 */
/* 函数内只打印了帧ID,未对数据部分做处理 */
void USB_LP_CAN1_RX0_IRQHandler(void)
{
    CanRxMsg CanRxMsg_Structure;

    if(SET == CAN_GetITStatus(CAN1, CAN_IT_FMP0))
    {
        /* receive data and clear interrupt pending bit */
        CAN_Receive(CAN1, CAN_FIFO0, &CanRxMsg_Structure);
        
        if(CanRxMsg_Structure.IDE == CAN_ID_STD)//标准帧
            printf("0x%04x\r\n",CanRxMsg_Structure.StdId);
        else                                    //扩展帧
            printf("0x%08x\r\n",CanRxMsg_Structure.ExtId);
    }
}





/* printf函数映射到 USART3 ,根据实际配置映射*/
#pragma import(__use_no_semihosting)

struct __FILE 
{
	int handle;

};

FILE __stdout;


int _sys_exit(int x)
{
	x = x;
    return 0;
}

int fputc(int ch, FILE *f)
{      
	USARTx_Send_Single_Byte(USART3,ch);
	return ch;
}

/*****END OF FILE****/

串口打印内容

在这里插入图片描述

后记

本人水平有限,如有错误,望不吝灵赐教

  • 3
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这里提供一个简单的示例代码,展示如何在STC89C52和STM32F103VE之间使用CAN通信: STC89C52代码: ```c #include <REG52.H> #include <intrins.h> #define CAN_SPEED 250000 // CAN总线速率 sbit P1_0 = P1^0; // LED指示灯 unsigned char Can_Init_Flags; // CAN初始化标志 unsigned char Can_Rx_Msg_Flags; // CAN消息接收标志 unsigned char Can_Tx_Msg_Flags; // CAN消息发送标志 unsigned char Can_Err_Msg_Flags; // CAN错误消息标志 unsigned char Can_Msg_Priority; // CAN消息优先级 unsigned char Can_Msg_Length; // CAN消息长度 unsigned char Can_Msg_Data[8]; // CAN消息数据 // CAN初始化函数 void Can_Init() { Can_Init_Flags = 0; // P1.0配置为输出 P1_0 = 0; // 定时器0初始化 TMOD &= 0xF0; TMOD |= 0x01; TH0 = 0xFC; TL0 = 0x67; ET0 = 1; TR0 = 1; // CAN初始化 Can_Init_Flags = CAN_Init_Mode(CAN_SPEED); if (Can_Init_Flags == 0x00) { P1_0 = 1; // 初始化成功,LED指示灯亮 } else { P1_0 = 0; // 初始化失败,LED指示灯灭 } } // CAN消息接收函数 void Can_Receive_Msg() { Can_Rx_Msg_Flags = CAN_Rx_Msg(&Can_Msg_Priority, &Can_Msg_Length, Can_Msg_Data); if (Can_Rx_Msg_Flags == 0x00) { if (Can_Msg_Length == 1 && Can_Msg_Data[0] == 0x01) { P1_0 = 1; // 接收到0x01,LED指示灯亮 } else { P1_0 = 0; // 接收到其他数据,LED指示灯灭 } } } // CAN消息发送函数 void Can_Transmit_Msg() { Can_Tx_Msg_Flags = CAN_Tx_Msg(Can_Msg_Priority, Can_Msg_Length, Can_Msg_Data); if (Can_Tx_Msg_Flags == 0x00) { P1_0 = 1; // 发送成功,LED指示灯亮 } else { P1_0 = 0; // 发送失败,LED指示灯灭 } } // 定时器0中断函数 void Timer0_ISR() interrupt 1 { Can_Receive_Msg(); // 接收CAN消息 } // 主函数 void main() { Can_Init(); // CAN初始化 while (1) { Can_Msg_Priority = 0x00; // CAN消息优先级 Can_Msg_Length = 1; // CAN消息长度 Can_Msg_Data[0] = 0x01; // CAN消息数据 Can_Transmit_Msg(); // 发送CAN消息 Delay50ms(); // 延时50ms } } ``` STM32F103VE代码: ```c #include "stm32f10x.h" #define CAN_SPEED 250000 // CAN总线速率 GPIO_InitTypeDef GPIO_InitStructure; // GPIO初始化结构体 CAN_InitTypeDef CAN_InitStructure; // CAN初始化结构体 CAN_FilterInitTypeDef CAN_FilterInitStructure; // CAN过滤器初始化结构体 CanTxMsg TxMessage; // CAN发送消息结构体 CanRxMsg RxMessage; // CAN接收消息结构体 // 延时函数 void Delay(uint32_t nCount) { for(; nCount != 0; nCount--); } // GPIO初始化函数 void GPIO_Configuration(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // 使能GPIOA时钟 // PA11(CAN1-Rx)、PA12(CAN1-Tx)配置为复用推挽输出 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOA, &GPIO_InitStructure); } // CAN初始化函数 void CAN_Configuration(void) { RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE); // 使能CAN1时钟 // CAN1初始化 CAN_InitStructure.CAN_TTCM = DISABLE; CAN_InitStructure.CAN_ABOM = DISABLE; CAN_InitStructure.CAN_AWUM = DISABLE; CAN_InitStructure.CAN_NART = DISABLE; CAN_InitStructure.CAN_RFLM = DISABLE; CAN_InitStructure.CAN_TXFP = DISABLE; CAN_InitStructure.CAN_Mode = CAN_Mode_Normal; CAN_InitStructure.CAN_SJW = CAN_SJW_1tq; CAN_InitStructure.CAN_BS1 = CAN_BS1_6tq; CAN_InitStructure.CAN_BS2 = CAN_BS2_8tq; CAN_InitStructure.CAN_Prescaler = 16; CAN_Init(CAN1, &CAN_InitStructure); // CAN过滤器初始化 CAN_FilterInitStructure.CAN_FilterNumber = 0; CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask; CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_32bit; CAN_FilterInitStructure.CAN_FilterIdHigh = 0x0000; CAN_FilterInitStructure.CAN_FilterIdLow = 0x0000; CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0x0000; CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0x0000; CAN_FilterInitStructure.CAN_FilterFIFOAssignment = 0; CAN_FilterInitStructure.CAN_FilterActivation = ENABLE; CAN_FilterInit(&CAN_FilterInitStructure); // CAN中断配置 NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x0F; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x00; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); // CAN接收中断使能 CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE); } // 发送CAN消息函数 void CAN_Send_Msg(uint8_t *Data, uint8_t DataLength) { TxMessage.StdId = 0x123; TxMessage.ExtId = 0; TxMessage.IDE = CAN_Id_Standard; TxMessage.RTR = CAN_RTR_Data; TxMessage.DLC = DataLength; for (int i = 0; i < DataLength; i++) { TxMessage.Data[i] = Data[i]; } CAN_Transmit(CAN1, &TxMessage); } // 接收CAN消息函数 void USB_LP_CAN1_RX0_IRQHandler(void) { CAN_Receive(CAN1, CAN_FIFO0, &RxMessage); if (RxMessage.StdId == 0x123 && RxMessage.IDE == CAN_Id_Standard && RxMessage.DLC == 1 && RxMessage.Data[0] == 0x01) { GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_SET); // 接收到0x01,PA0输出高电平 } else { GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_RESET); // 接收到其他数据,PA0输出低电平 } } // 主函数 int main(void) { // GPIO初始化 GPIO_Configuration(); // CAN初始化 CAN_Configuration(); // 发送CAN消息 uint8_t Data[] = {0x01}; while (1) { CAN_Send_Msg(Data, sizeof(Data)); Delay(0xFFFFF); // 延时 } } ``` 注意:本示例代码中,STC89C52使用P1.0作为LED指示灯,STM32F103VE使用PA0作为LED指示灯,需要根据自己的硬件连接情况进行修改。此外,还需要在STM32F103VE的`stm32f10x_it.c`文件中添加CAN接收中断处理函数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值