详解stm32的CAN控制器(程序分享)

控制/MCU

1878人已加入

描述

首先简单介绍一下CAN总线,关于CAN总线是谁发明的,CAN总线的历史,CAN总线的发展,CAN总线的应用场合,这些,通通不说。这里只是以我个人理解,简单说说CAN通信。CAN总线的端点没有地址(除非自己在帧里定义地址),CAN总线通信不用地址,用标识符,不是单独的谁发给谁,而是,你总是发送给整个网络。然后每个节点都有过滤器,对网络上的传播的帧的标识符进行过滤,自己想要什么样的帧,可以设置自己的过滤器,接收相关的帧信息。如果两个节点同时发送怎么办?这个不用我们担心,CAN控制器会自己仲裁,让高优先级的帧先发。

然后我们可以了解一下stm32的CAN控制器。

CAN控制器

如上图所示,stm32有两个can控制器,can1(主),和can2(从),其中过滤器的设置是通过can1来设置,其他工作模式,波特率等,可以各自设置。每个控制器有三个发送邮箱,两个fifo,每个fifo有三个接收邮箱。

发送:选择一个空的发送邮箱,把帧信息写到该发送邮箱的寄存器里,请求发送,控制器就会根据标识符的优先级把帧先后发送出去。

接收:如果接收到的帧的标识符能过过滤表的一系列过滤,该帧信息就会保存在fifo接收邮箱的寄存器里。

过滤器:stm32f407共有28组过滤器,每组过滤器可以设置关联到fifo0或者fifo1,每组都包括两个32位存储器,可以配置成一个32位有位屏蔽功能的标识符过滤器,或者两个32位完全匹配的标识符过滤器,或者两个16位有位屏蔽功能的标识符过滤器,或者四个16位完全匹配的标识符过滤器。如下图所示:

CAN控制器

我所说的完全匹配的意思是,接收到的帧的标识符每一位都要跟过滤器对应的位一样,才能过得了这个过滤器。有位屏蔽功能的意思是一个寄存器放标识符,一个放屏蔽掩码,屏蔽掩码为1的位对应的接收到的帧的标识符的位与对应的放标识符的寄存器的位一致,就能通过。

传输一位的时间和波特率的计算:

CAN控制器

CAN控制器的波特率是由APB时钟线和CAN位时序寄存器CAN_BTR的TS2[3:0]、TS1[2:0]和BRP[9:0]确定的,其中,TS1[2:0]定义了时间段1占用多少个时间单元,TS2[3:0]定义了时间段2占用多少个时间单元,BRP[9:0]定义对APB1时钟的分频。

PS:设置波特率为1M

CAN控制器

其中Tpclk为APB1的时钟周期,假设为

Tpclk = 1/42M

0≦TS1≦7

0≦TS2≦15

0≦BRP≦1021

根据以上数据,有

(TS2+TS1+3)(BRP+1)=42

令BRP=2,有

TS2+TS1=11

令TS1=8,TS2=3

设置步骤:

1. 设置中断优先级分组(如果之前没有设置),这个最好一个程序里只在开头设置一次。

2. 使能相关GPIO时钟。

3. 选择相关GPIO引脚的复用功能。

4. 设置相关GPIO引脚为复用模式。

5. 设置相关GPIO引脚的速度,方式。

6. 设置主控制寄存器MCR,进入初始化模式

7. 等待进入初始化模式

8. 设置波特率。

9. 其他设置。

10. 如果要用到中断,在中断使能寄存器IER中使能相关中断响应。

11. 如果要用到中断,设置相关中断优先级(NVIC_IP)。

12. 如果要用到中断,使能相关中断(NVIC_ISER)。

13. 设置主控制寄存器MCR,进入正常工作模式。

14. 设置FMR,使过滤器组工作在初始化模式。

15. 设置FMR的CAN2SB,确定CAN2的过滤器组从哪一组开始。

16. 设置用到的过滤器组的工作方式。

17. 设置用到的过滤器组的位宽。

18. 给fifo0和fifo2划分(关联)过滤组。

19. 禁用用到的过滤器组。

20. 设置过滤器组的标识符,帧类型等。

21. 使能相关过滤器组。

22. 设置FMR,使过滤器组工作在正常模式。

23. 如果要用中断,编写中断服务函数(函数名是固定的)。

24. 中断服务函数里检查是哪个中断。

25. 编写相应服务程序。

电路请参见本博客:小工具之——CAN收发器

程序:

[plain] view plaincopy/************************************

标题:操作CAN的练习

软件平台:IAR for ARM6.21

硬件平台:stm32f4-discovery

主频:168M

描述:通过硬件收发器连接CAN1,CAN2

组成一个两个端点的网络

CAN1循环发出数据帧

CAN2接收过滤数据帧

用uart把CAN2接收到

的数据帧发到超级终端

author:小船

data:2012-08-14

*************************************/

#include 《stm32f4xx.h》

#include “MyDebugger.h”

#define RECEIVE_BUFFER_SIZE 20

u32 CAN2_receive_buffer[RECEIVE_BUFFER_SIZE][4];

u8 UART_send_buffer[1800];

u8 Consumer = 0;

u8 Producer = 0;

u32 Gb_TimingDelay;

void Delay(uint32_t nTime);

void TIM7_init();//定时1s

u32 get_rece_data();

void CAN_GPIO_config();

void main ()

{

u32 empty_box;

SysTick_Config(SystemCoreClock / 1000); //设置systemtick一毫秒中断

SCB-》AIRCR = 0x05FA0000 | 0x400; //中断优先级分组 抢占:响应=3:1

MyDebugger_Init();

TIM7_init();

MyDebugger_Message( “\n\rtesting.。。.。。\n\r” ,

sizeof(“\n\rtesting.。。.。。\n\r”)/sizeof(char) );

CAN_GPIO_config();

RCC-》APB1ENR |= ((1《《25)|(1《《26));//使能CAN1、CAN2时钟

CAN1-》MCR = 0x00000000;

/*

请求进入初始化模式

禁止报文自动重传

自动唤醒模式

*/

CAN1-》MCR |= ((1《《0)|(1《《4)|(1《《5));

CAN1-》MCR &= ~(1《《16);//在调试时,CAN照常工作

while(!(CAN1-》MSR & 0xfffffffe)) //等待进入初始化模式

{

MyDebugger_LEDs(orange, on);

}

MyDebugger_LEDs(orange, off);

/*

正常模式

重新同步跳跃宽度(1+1)tq

TS2[2:0]=3

TS1[3:0]=8

BRP[9:0]=2

ps:

tq = (BRP[9:0] + 1) x tPCLK,

tBS2 = tq x (TS2[2:0] + 1),

tBS1 = tq x (TS1[3:0] + 1),

NominalBitTime = 1 × tq+tBS1+tBS2,

BaudRate = 1 / NominalBitTime

波特率设为1M

*/

CAN1-》BTR = ((0《《30)|(0x01《《24)|(3《《20)|(8《《16)|(2《《0));

CAN1-》MCR &= ~(0x00000001);//正常工作模式

CAN2-》MCR = 0x00000000;

/*

请求进入初始化模式

禁止报文自动重传

自动唤醒模式

*/

CAN2-》MCR |= ((1《《0)|(1《《4)|(1《《5));

CAN2-》MCR &= ~(1《《16);//在调试时,CAN照常工作

while(!(CAN2-》MSR & 0xfffffffe)) //等待进入初始化模式

{

MyDebugger_LEDs(orange, on);

}

MyDebugger_LEDs(orange, off);

/*

正常模式

重新同步跳跃宽度(1+1)tq

TS2[2:0]=3

TS1[3:0]=8

BRP[9:0]=2

ps:

tq = (BRP[9:0] + 1) x tPCLK,

tBS2 = tq x (TS2[2:0] + 1),

tBS1 = tq x (TS1[3:0] + 1),

NominalBitTime = 1 × tq+tBS1+tBS2,

BaudRate = 1 / NominalBitTime

波特率设为1M

*/

CAN2-》BTR = ((0《《30)|(0x01《《24)|(3《《20)|(8《《16)|(2《《0));

CAN2-》IER &= 0x00000000;

/*

FIFO1消息挂号中断使能

FIFO1满中断使能

FIFO1溢出中断使能

*/

CAN2-》IER |= ((1《《4)|(1《《5)|(1《《6));

NVIC-》IP[65] = 0xa0; //抢占优先级101,响应优先级0

NVIC-》ISER[2] |= (1《《1); //使能中断线65,也就是can2_rx1中断

CAN2-》MCR &= ~(0x00000001);//正常工作模式

//总共有28组过滤器

CAN1-》FMR |= 1; //过滤器组工作在初始化模式

CAN1-》FMR &= 0xffffc0ff;//CAN2的过滤器组从14开始

CAN1-》FMR |= (14《《8);

CAN1-》FM1R |= (1《《14);//过滤器组14的寄存器工作在标识符列表模式

//位宽为16位,2个32位分为四个16位寄存器,过滤四个标识符

//CAN1-》FS1R |= (1《《15);//过滤器组15为单个32位寄存器,用于扩展标识符

CAN1-》FFA1R = 0x0fffc000;//0~13号过滤器组关联到fifo0,14~27号过滤器组关联到fifo1

CAN1-》FA1R &= ~(1《《14);//禁用过滤器组14

/*

过滤器组0寄存器分为4个十六位过滤器:

标识符列表:

过滤器编号 匹配标准标识符 RTR IDE EXID[17:15]

0 0x7cb(111 1100 1011b) 数据帧 标准标识符 000b

1 0x4ab(100 1010 1011b) 数据帧 标准标识符 000b

2 0x7ab(111 1010 1011b) 数据帧 标准标识符 000b

3 0x40b(100 0000 1011b) 数据帧 标准标识符 000b

*/

CAN1-》sFilterRegister[14].FR1 &= 0x00000000;

CAN1-》sFilterRegister[14].FR2 &= 0x00000000;

CAN1-》sFilterRegister[14].FR1 |= ((0x7cb《《5)|(0《《4)|(0《《3));

CAN1-》sFilterRegister[14].FR1 |= ((0x4ab《《21)|(0《《20)|(0《《19));

CAN1-》sFilterRegister[14].FR2 |= ((0x7ab《《5)|(0《《4)|(0《《3));

CAN1-》sFilterRegister[14].FR2 |= ((0x40b《《21)|(0《《20)|(0《《19));

CAN1-》FA1R |= (1《《14);//使能过滤器组14

CAN1-》FMR &= ~1; //过滤器组正常工作

while(1)

{

/*

选择空的发送邮箱:

标准标识符0x7ab(111 1010 1011b)

数据帧

不使用扩展标识符

*/

if( CAN1-》TSR & ((1《《26)|(1《《27)|(1《《28)) )

{

empty_box = ((CAN1-》TSR》》24) & 0x00000003);

CAN1-》sTxMailBox[empty_box].TIR = (0x7ab《《21);

CAN1-》sTxMailBox[empty_box].TDTR &= 0xfffffff0;

CAN1-》sTxMailBox[empty_box].TDTR |= 0x00000008;//发送数据长度为8

CAN1-》sTxMailBox[empty_box].TDLR = 0x12345678;

CAN1-》sTxMailBox[empty_box].TDHR = 0x9abcdef0;

CAN1-》sTxMailBox[empty_box].TIR |= (1《《0);//请求发送

}

else

{

MyDebugger_LEDs(orange, on);

}

Delay(100);

/*

选择空的发送邮箱:

标准标识符0x4ab(100 1010 1011b)

数据帧

不使用扩展标识符

*/

if( CAN1-》TSR & ((1《《26)|(1《《27)|(1《《28)) )

{

empty_box = ((CAN1-》TSR》》24) & 0x00000003);

CAN1-》sTxMailBox[empty_box].TIR = (0x4ab《《21);

CAN1-》sTxMailBox[empty_box].TDTR &= 0xfffffff0;

CAN1-》sTxMailBox[empty_box].TDTR |= 0x00000008;//发送数据长度为8

CAN1-》sTxMailBox[empty_box].TDLR = 0x56781234;

CAN1-》sTxMailBox[empty_box].TDHR = 0x9abcdef0;

CAN1-》sTxMailBox[empty_box].TIR |= (1《《0);//请求发送

}

else

{

MyDebugger_LEDs(orange, on);

}

Delay(100);

/*

选择空的发送邮箱:

标准标识符0x7cb(100 1010 1011b)

数据帧

不使用扩展标识符

*/

if( CAN1-》TSR & ((1《《26)|(1《《27)|(1《《28)) )

{

empty_box = ((CAN1-》TSR》》24) & 0x00000003);

CAN1-》sTxMailBox[empty_box].TIR = (0x7cb《《21);

CAN1-》sTxMailBox[empty_box].TDTR &= 0xfffffff0;

CAN1-》sTxMailBox[empty_box].TDTR |= 0x00000006;//发送数据长度为6

CAN1-》sTxMailBox[empty_box].TDLR = 0x56781234;

CAN1-》sTxMailBox[empty_box].TDHR = 0x00009abc;

CAN1-》sTxMailBox[empty_box].TIR |= (1《《0);//请求发送

}

else

{

MyDebugger_LEDs(orange, on);

}

Delay(100);

/*

选择空的发送邮箱:

标准标识符0x40b(100 0000 1011b)

数据帧

不使用扩展标识符

*/

if( CAN1-》TSR & ((1《《26)|(1《《27)|(1《《28)) )

{

empty_box = ((CAN1-》TSR》》24) & 0x00000003);

CAN1-》sTxMailBox[empty_box].TIR = (0x40b《《21);

CAN1-》sTxMailBox[empty_box].TDTR &= 0xfffffff0;

CAN1-》sTxMailBox[empty_box].TDTR |= 0x00000004;//发送数据长度为4

CAN1-》sTxMailBox[empty_box].TDLR = 0x56781234;

CAN1-》sTxMailBox[empty_box].TDHR = 0x00000000;

CAN1-》sTxMailBox[empty_box].TIR |= (1《《0);//请求发送

}

else

{

MyDebugger_LEDs(orange, on);

}

Delay(100);

}

}

/****************************************

函数名:CAN_GPIO_config

参数:无

返回值:无

功能:设置CAN1,2控制器用到IO口

CAN1_TX---------PD1

CAN1_RX---------PB8

CAN2_TX---------PB13

CAN2_RX---------PB5

****************************************/

void CAN_GPIO_config()

{

RCC-》AHB1ENR |= ((1《《1) | (1《《3));//使能GPIOB、D时钟

GPIOB-》AFR[0] |= 0x00900000; //AF9

GPIOB-》AFR[1] |= 0x00900009;

GPIOD-》AFR[0] |= 0x00000090;

GPIOB-》MODER &= 0xF3FCF3FF; //第二功能

GPIOB-》MODER |= 0x08020800;

GPIOD-》MODER &= 0xFFFFFFF3;

GPIOD-》MODER |= 0x00000008;

GPIOB-》OSPEEDR &= 0xF3FCF3FF; //50M

GPIOB-》OSPEEDR |= 0x08020800;

GPIOD-》OSPEEDR &= 0xFFFFFFF3;

GPIOD-》OSPEEDR |= 0x00000008;

GPIOB-》PUPDR &= 0xF3FCF3FF; //上拉

GPIOB-》PUPDR |= 0x04010400;

GPIOD-》PUPDR &= 0xFFFFFFF3;

GPIOD-》PUPDR |= 0x00000004;

}

/****************************************

函数名:CAN2_RX1_IRQHandler

参数:无

返回值:无

功能:CAN2fifo1接收中断处理

把信息存进循环队列

****************************************/

void CAN2_RX1_IRQHandler()

{

if(CAN2-》RF1R & (0x00000003))//接收到新的消息,fifo1非空

{

Producer++;

if(Producer == RECEIVE_BUFFER_SIZE)Producer = 0;

if(Producer != Consumer)

{

CAN2_receive_buffer[Producer][0] = CAN2-》sFIFOMailBox[1].RIR;

CAN2_receive_buffer[Producer][1] = CAN2-》sFIFOMailBox[1].RDTR;

CAN2_receive_buffer[Producer][2] = CAN2-》sFIFOMailBox[1].RDLR;

CAN2_receive_buffer[Producer][3] = CAN2-》sFIFOMailBox[1].RDHR;

}

else

{

if(Producer == 0)Producer = RECEIVE_BUFFER_SIZE;

Producer--;

MyDebugger_LEDs(blue, on);

}

CAN2-》RF1R |= (1《《5);//释放邮箱

}

if(CAN2-》RF1R & (1《《3))//fifo0满

{

MyDebugger_LEDs(red, on);

CAN2-》RF1R &= ~(1《《3);

}

if(CAN2-》RF1R & (1《《4))//fifo0溢出

{

MyDebugger_LEDs(red, on);

CAN2-》RF1R &= ~(1《《4);

}

}

/****************************************

函数名:TIM7_init

参数:无

返回值:无

功能:初始化定时器7

作1s定时用

****************************************/

void TIM7_init()

{

RCC-》APB1ENR |= (1《《5); //打开TIM7时钟

TIM7-》PSC = 8399; //对时钟84M进行8400分频,使得计数频率为10k

TIM7-》ARR = 10000; //定时一秒

TIM7-》CNT = 0; //清空计数器

TIM7-》CR1 |= (1《《7); //自动重装载预装载使能

TIM7-》DIER |= 1; //使能中断

NVIC-》IP[55] = 0xe0;

NVIC-》ISER[1] |= (1《《(55-32));

TIM7-》CR1 |= 1; //开始计时

}

/****************************************

函数名:TIM7_IRQHandler

参数:无

返回值:无

功能:定时器7中断处理

1s定时到

把can2收到的信息转换格式

用usrt发送到超级终端显示

****************************************/

void TIM7_IRQHandler(void)

{

u32 length;

if(TIM7-》SR)

{

length = get_rece_data();

MyDebugger_Message( UART_send_buffer, length );

TIM7-》SR &= ~(0x0001);

}

}

/****************************************

函数名:get_rece_data

参数:无

返回值:length 整理后要发送数据的长度

功能:把循环队列的信息取出

进行格式转换

把信息存到uart发送缓冲区

****************************************/

u32 get_rece_data()

{

u8 filter_No;

u8 Data_length;

char i;

u32 length = 0;

const char ascii[16] = {‘0’, ‘1’, ‘2’, ‘3’, ‘4’, ‘5’, ‘6’, ‘7’,

‘8’, ‘9’, ‘A’, ‘B’, ‘C’, ‘D’, ‘E’, ‘F’};

while(1)

{

if(Producer != Consumer)

{

Consumer++;

if(Consumer == RECEIVE_BUFFER_SIZE)Consumer=0;

UART_send_buffer[length++] = ‘\n’;

UART_send_buffer[length++] = ‘\r’;

//Filter No.xx

UART_send_buffer[length++] = ‘F’;

UART_send_buffer[length++] = ‘i’;

UART_send_buffer[length++] = ‘l’;

UART_send_buffer[length++] = ‘t’;

UART_send_buffer[length++] = ‘e’;

UART_send_buffer[length++] = ‘r’;

UART_send_buffer[length++] = ‘ ’;

UART_send_buffer[length++] = ‘N’;

UART_send_buffer[length++] = ‘o’;

UART_send_buffer[length++] = ‘。’;

filter_No = (CAN2_receive_buffer[Consumer][1]》》8) & 0x000000ff;

UART_send_buffer[length++] = filter_No%100/10 + ‘0’;

UART_send_buffer[length++] = filter_No%10 + ‘0’;

UART_send_buffer[length++] = ‘\n’;

UART_send_buffer[length++] = ‘\r’;

//DataLength:x

UART_send_buffer[length++] = ‘D’;

UART_send_buffer[length++] = ‘a’;

UART_send_buffer[length++] = ‘t’;

UART_send_buffer[length++] = ‘a’;

UART_send_buffer[length++] = ‘L’;

UART_send_buffer[length++] = ‘e’;

UART_send_buffer[length++] = ‘n’;

UART_send_buffer[length++] = ‘g’;

UART_send_buffer[length++] = ‘t’;

UART_send_buffer[length++] = ‘h’;

UART_send_buffer[length++] = ‘:’;

Data_length = CAN2_receive_buffer[Consumer][1] & 0x0000000f;

UART_send_buffer[length++] = Data_length % 10 + ‘0’;

UART_send_buffer[length++] = ‘\n’;

UART_send_buffer[length++] = ‘\r’;

if(CAN2_receive_buffer[Consumer][0] & (1《《1))

{

UART_send_buffer[length++] = ‘R’;

UART_send_buffer[length++] = ‘e’;

UART_send_buffer[length++] = ‘m’;

UART_send_buffer[length++] = ‘o’;

UART_send_buffer[length++] = ‘t’;

UART_send_buffer[length++] = ‘e’;

UART_send_buffer[length++] = ‘F’;

UART_send_buffer[length++] = ‘r’;

UART_send_buffer[length++] = ‘a’;

UART_send_buffer[length++] = ‘m’;

UART_send_buffer[length++] = ‘e’;

}

else

{

UART_send_buffer[length++] = ‘D’;

UART_send_buffer[length++] = ‘a’;

UART_send_buffer[length++] = ‘t’;

UART_send_buffer[length++] = ‘a’;

UART_send_buffer[length++] = ‘F’;

UART_send_buffer[length++] = ‘r’;

UART_send_buffer[length++] = ‘a’;

UART_send_buffer[length++] = ‘m’;

UART_send_buffer[length++] = ‘e’;

}

UART_send_buffer[length++] = ‘\n’;

UART_send_buffer[length++] = ‘\r’;

if(CAN2_receive_buffer[Consumer][0] & (1《《2))

{

UART_send_buffer[length++] = ‘e’;

UART_send_buffer[length++] = ‘x’;

UART_send_buffer[length++] = ‘t’;

UART_send_buffer[length++] = ‘ ’;

UART_send_buffer[length++] = ‘I’;

UART_send_buffer[length++] = ‘D’;

UART_send_buffer[length++] = ‘:’;

UART_send_buffer[length++] =

ascii[CAN2_receive_buffer[Consumer][0] 》》 31];

UART_send_buffer[length++] =

ascii[(CAN2_receive_buffer[Consumer][0] 》》 27)& 0x0000000f];

UART_send_buffer[length++] =

ascii[(CAN2_receive_buffer[Consumer][0] 》》 23)& 0x0000000f];

UART_send_buffer[length++] =

ascii[(CAN2_receive_buffer[Consumer][0] 》》 19)& 0x0000000f];

UART_send_buffer[length++] =

ascii[(CAN2_receive_buffer[Consumer][0] 》》 15)& 0x0000000f];

UART_send_buffer[length++] =

ascii[(CAN2_receive_buffer[Consumer][0] 》》 11)& 0x0000000f];

UART_send_buffer[length++] =

ascii[(CAN2_receive_buffer[Consumer][0] 》》 7)& 0x0000000f];

UART_send_buffer[length++] =

ascii[(CAN2_receive_buffer[Consumer][0] 》》 3)& 0x0000000f];

}

else

{

UART_send_buffer[length++] = ‘s’;

UART_send_buffer[length++] = ‘t’;

UART_send_buffer[length++] = ‘d’;

UART_send_buffer[length++] = ‘ ’;

UART_send_buffer[length++] = ‘I’;

UART_send_buffer[length++] = ‘D’;

UART_send_buffer[length++] = ‘:’;

UART_send_buffer[length++] =

ascii[CAN2_receive_buffer[Consumer][0] 》》 29];

UART_send_buffer[length++] =

ascii[(CAN2_receive_buffer[Consumer][0] 》》 25)& 0x0000000f];

UART_send_buffer[length++] =

ascii[(CAN2_receive_buffer[Consumer][0] 》》 21)& 0x0000000f];

}

UART_send_buffer[length++] = ‘\n’;

UART_send_buffer[length++] = ‘\r’;

UART_send_buffer[length++] = ‘D’;

UART_send_buffer[length++] = ‘a’;

UART_send_buffer[length++] = ‘t’;

UART_send_buffer[length++] = ‘a’;

UART_send_buffer[length++] = ‘:’;

if(Data_length 》 4)

{

for(i = 2*Data_length - 8; i 》 0; i--)

UART_send_buffer[length++] =

ascii[(CAN2_receive_buffer[Consumer][3] 》》 ((i-1)*4))& 0x0000000f];

for(i = 8; i 》 0; i--)

UART_send_buffer[length++] =

ascii[(CAN2_receive_buffer[Consumer][2] 》》 ((i-1)*4))& 0x0000000f];

}

else

{

for(i = 2*Data_length; i 》 0; i--)

UART_send_buffer[length++] =

ascii[(CAN2_receive_buffer[Consumer][2] 》》 ((i-1)*4))& 0x0000000f];

}

UART_send_buffer[length++] = ‘\n’;

UART_send_buffer[length++] = ‘\r’;

}

else

break;

}

return length;

}

void Delay(uint32_t nTime)

{

Gb_TimingDelay = nTime;

while(Gb_TimingDelay != 0);

}

void SysTick_Handler(void)

{

if (Gb_TimingDelay != 0x00)

{

Gb_TimingDelay--;

}

}

运行结果:

CAN控制器

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分