这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » STM32 » 基于can通信的设计

共6条 1/1 1 跳转至

基于can通信的设计

菜鸟
2015-12-11 09:12:00     打赏
我们要使用的 CAN1 所以我们讲 CAN1 的时钟,还有要使用的 IO 口的 时钟。在这里我们看到 CAN 还有编号!其实呢,在互联型的 STM32 中是有 两个 CAN 的,一个主 CAN
一个从 CAN,不过我们开发板上面使用的是增 强型不是互联型,所以只有一个 CAN。
所以设置代码为: RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);

2.    配置 IO 的模式
我们使用的收发 IO 口是 PA11 和 PA12。在这里我们要把 PA11 设置为上
拉 输 入 : GPIO_Mode_IPD , PA12   设 置 为 复 用 推 挽 输 出 :
GPIO_Mode_AF_PP。代码为:
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;                //PA12
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure);

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;          //上拉输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;                //PA11


GPIO_Init(GPIOA, &GPIO_InitStructure);


3.    复位 CAN 外设及结构体函数。 我们使用的初始化的结构体成员很多,有时候有些成员不用设置,所以
我们复位初始化一下。代码为: CAN_DeInit(CAN1); CAN_StructInit(&CAN_InitStructure);

4.    初始化 CAN
初始化 CAN 我们调用 CAN_Init()这个函数,这个函数跟其他的初始化函
数一样,有两个参数。
第一个参数用来选择你要初始化的 CAN,我们初始化 CAN1 所以设置为:
CAN1。
第二个参数是传递一个结构体指针。这个结构体里面包含了各种 CAN
的设置,对于理解 CAN 通信非常重要,接下来我们就来详细讲解一下这个

结构体的各个成员所代表的意义。
1)   CAN_TTCM:表示是否使用时间触发模式。那什么是时间触发模式
呢?时间触发通信模式下,CAN 硬件的内部定时器被激活,并且被
用于产生时间戳,分别存储在 CAN_RDTxR/CAN_TDTxR 寄存器中。
内部定时器在接收和发送的帧起始位的采样点位置被采样,并生成
时间戳,禁止自动重传模式,主要用于满足 CAN 标准中时间触发通
信选项的要求。在该模式下,发送操作只会执行一次。如果发送操
作失败了,不管是由于仲裁丢失或出错,硬件都不会再自动发送该
报文。在一次发送操作结束后,硬件认为发送请求已经完成,从而
对  CAN_TSR  寄 存器的  RQCP  位置  1,同时发送的结果反映在
CAN_TSR 寄存器的 TXOK、ALST 和 TERR 位上。我们这里不使用
时间触发模式,所以我们设置为:DISABLE
2)   CAN_ABOM:表示是否使用自动离线管理。什么是自动离线管理
呢?其实设置当 CAN 处在离线状态下时,是否能够离开离线状态。
当它使能的时候,单片机工作的过程是:当硬件检测到 128 次 11 位
连续的隐形位,就自动退出离线状态;当它失能的时候,需要用软
件来设置 CAN_MCR 寄存器中的 INRQ,然后当硬件检测到 128 次
11 位连续的隐形位,就退出离线状态。现在我们知道自动离线管理
是怎么回事儿了,但是呢,我们又有点疑问,离线状态是怎么事儿?
这个呢,它是当 TEC 大于 255 时,BxCAN 就进入离线状态,那 TEC
又是什么呢?TEC 呢其实是一个 9 位的发送错误计数器的低 8 位,
在 CAN_ESR 寄存器里面,然后它根据 CAN 标准,接收出错时,根
据出错的条件,加 1 或者加 8。(详细的错误标准大家可以查看 CAN
手册)现在我们恍然大悟了吧,其实离线状态是 CAN  出错了之后
CAN 进入的状态。(所以我们说 CAN 有故障隔离机制就是这么回事)
我们这里不使用,那么设置为:DISABLE。
3)   CAN_AWUM:表示是否使用睡眠模式自动唤醒。在 CAN 正常工作
的时候有三种模式,一种是初始化模式,一种是正常模式和一种睡
眠模式。只有在正常模式的时候,CAN 才能正常收发报文。一般睡
眠模式是工作在低功耗下休眠的。我们这里不使用,所以设置为:
DISABLE。
4)   CAN_NART:表示是否使用非自动重传输。按照 CAN 标准,CAN
硬件在发送报文失败时会一直自动重传直到发送成功。(在时间模式
下不使用。)我们这里要使用自动重传输,设置为:DISABLE。
5)   CAN_RFLM:表示是否使用 FIFO 锁定模式。这个 FIFO 锁定模式的
意义在于,FIFO 未被锁定时,接收溢出时,当接收 FIFO 的报文未
被读出,下一个收到的报文会覆盖原有的报文;FIFO 被锁定时,接
收溢出时,当接收 FIFO 的报文未被读出,下一个收到的报文会被丢
弃。我们这里不锁定,也就是新数据会覆盖旧数据,所以设置为:
DISABLE。
6)   CAN_TXFP:表示发送的优先级选择。在这里我们先来看个图:

从图上我们可以看出,CAN 的发送邮箱一共有三个,也就是说我们 发送的时候,可以同时有三个报文同时等待发送,那么这个成员的意义 就是选择优先级的规则。当它使能的时候优先级由发送请求的顺序来决
定;当它使能的时候优先级由报文的标识符来决定。我们这里由标示符 来决定,设置为:DISABLE。
    CAN_Mode:表示选择 CAN 要使用的模式。在 CAN 模式类别中, 可以分为:工作模式和测试模式。工作模式我们上面有提到过一下,
主要有初始化模式、正常模式和睡眠模式。测试模式有静默模式、 环回模式和静默环回模式。我们正常通信的时候,一般使用的是正 常模式。不过我们测试可以使用环回模式,在环回模式下,bxCAN
把发送的报文当作接收的报文并保存(如果可以通过接收过滤)在接 收邮箱里。在库函数中它提供了四种模式选择,如下图:




















 CAN_SJW:表示设置重新同步跳跃宽度。即在每位中可以延长或缩 短多少个时间单位的上限。大家不理解也没有关系,我们这里设置 为 1 个时间单位:CAN_SJW_1tq。

    CAN_BS1:这个参数和下面的 CAN_BS2、CAN_Prescaler。来决定 CAN 总线的波特率的。(设置波特率要注意,要根据 CAN 总线上面 的波特率来设置,也就是说同一个
CAN 总线上面的波特率要相同 的。)我们先来看一下波特率的公式它是怎么算的:








那么我们根据上面的公式,我们知道,只要我们知道 TBS1、TBS2 和 Tq, 然后在知道 APB1 时钟周期,那么我们就可以算出 CAN 的波特率。根据上面 的公式,一般 APB1 的时钟为
36MHZ,那么我们可以推导出:波特率 = 36K
/ ((CAN_BS1 + CAN_BS2 + 1) * CAN_Prescaler),比如我们设置 CAN_BS1 =
8,CAN_BS2 = 7,CAN_Prescaler = 5 时,波特率就是 450K。
    CAN_BS2:参与设置波特率,可以查看 CAN_BS2 的设置。
    CAN_Prescaler:参与设置波特率,可以查看 CAN_BS2 的设置。

5.    CAN 的发送
讲了 CAN 的初始化,那么我们接着来讲怎么使用 CAN 来发送数据。数
据的发送流程为:应用程序选择 1 个空置的发送邮箱;设置标识符,数据长
度和待发送数据;然后对 CAN_TIxR 寄存器的 TXRQ 位置’1’,来请求发
送。那么首先我们先来配置邮箱,并将要传送的数据放入到邮箱里面。
数据发送可以使用 CAN_Transmit()函数来发送,这个函数有两个参数:
第一个参数为选择你要使用的 CAN,我们使用 CAN 就设置为 CAN1。
第二个参数传递一个结构体 CanTxMsg 的指针。这个结构体的成员有:
    StdId:表示标准的 ID。
    ExtId:表示拓展的 ID。
    RTR:表示发送的帧类型。如:数据帧、远程帧等。
    IDE:表示要发送的是标准帧还是拓展帧。
    DLC 表示发送的数据长度。
    Data:这个是以个 8 个成员的数据,也就是用来存放你要发送的数
据。
设置完了,我们就可以调用 CAN_Transmit()函数来发送了,不过它还提

供了一个返回值,是发送的邮箱标号,以让我们好擦看发送的状态。发送的 详细代码可以看程序里面的发送函数。

6.    CAN 的数据接收
在 CAN  协议里,报文的标识符不代表节点的地址,而是跟报文的内容
相关的。因此,发送者乙广播的形式把报文发送给所有的接收者。节点在接
收报文时根据标识符的值决定软件是否需要该报文;如果需要,就拷贝到
SRAM 里;如果不需要,报文就被丢弃且无需软件的干预。
在这里呢,首先来了解一下 CAN 的过滤器,在 CAN 中,为了方便接收
我们想要的 ID,它设有一个过滤器,用来过滤掉我们不想要的 ID。,在互联
型的产品中它一共有 28 组过滤器,而其它产品中有 14 组过滤器。而每一组
过滤器呢又有两个 32 位的寄存器。
接下来我们来看一下 CAN 的屏蔽模式,CAN 的屏蔽模式有两种,一种
是屏蔽位模式,一种是屏蔽列表模式。那什么是屏蔽位模式和屏蔽列表模式
呢?
在屏蔽位模式下呢,每组过滤器中的两个寄存器分为标示符寄存器和屏
蔽寄存器两种,标示符寄存器用来设置你想接收的 ID,而屏蔽寄存器呢,用
来设置你关心的位(即你想比较的位)。如说:标准格式 11 位的 ID 里面,
你只关心第一位,它必须为 1,其他位你不关心,那么你就可以设置屏蔽寄
存器第一位为 1(也就是必须比较),然后设置标示符寄存器的第一位也为
1(也就是要跟 1 比较),这样子 CAN 接收的时候它就只比较接收的 ID 第一位
是 1 的 ID,其他它不管。又比如说,当你值接收一个固定的 ID 的时候,你
把屏蔽寄存器全部设置为 1(即必须比较),然后在标示符寄存器里面存放你
想要的接收的 ID,那么当 CAN 总线上面出现你想要的 ID 的时候,它就将
它接收,其他的不接收。
在屏蔽列表模式下呢,就更加简单了,在屏蔽列表模式下,每组过滤器
中的两个寄存器全部用来做标示符寄存器,也就是说当接收的 ID 必须跟表
示符寄存器中的 ID 相同的时候才接收。
明白了屏蔽寄存器和标示符寄存器的作用之后,我们来看一下过滤器的
结构,首先我们要了解过滤器是可以设置成两种模式的,一种是 16 位的,
一种是 32 位的,毕竟我们的 ID 可以分为标准 ID(11 位)和拓展 ID(29 位)。
接下来我们来看一个图:

上面这个寄存器组结构呢,就是过滤器组的结构。通过上图我们看到四 种四组寄存器的说明。分别是 16 位的屏蔽位模式、32 位的屏蔽位模式、16 位的标示符列表模式、32
的标示符列表模式。在上面的图中,有个地方,我 们要注意了!!就是寄存器中 ID 的起始位置!因为在下面我们设置接收过 滤器的时候,是要设置接收 ID,当时 ID 在寄存器中起始位置并不是从寄存
器一开始的。上面图中的 STID 才是 ID,EXID 是拓展 ID,IDE 是标准帧和 拓展帧的标示。
我们现在了解了,CAN 过滤器的结构之后我们接下来看一下怎么使用库 函数来设置 CAN 的过滤器。
我们可以通过 CAN_FilterInit()函数来设置,这个函数有一个参数,就是 传递一个结构体的指针,这个结构体的成员主要有:
    CAN_FilterIdHigh:表示标示符寄存器的 ID。CAN_FilterIdHigh:表 示接收的过滤器。在这里呢,它可以填 0~13 里面的任意数。(不过 在库函数说明中它却说是
1 到 13,这个有点奇怪,在数据手册中是 说有 14 组过滤器的,不过我试过了 0 也是可以过滤的。如若哪里有 错的,欢迎大家指正。)我们这里使用第一组寄存器设置为:1。
  CAN_FilterMode:表示过滤模式。我们上面讲到它有屏蔽位模式和 标 示 符 列 表 模 式 。 我 们 使 用 屏 蔽 位 模 式 , 所 以 设 置 为 :
CAN_FilterMode_IdMask。
    CAN_FilterScale:表示设置过滤器的长度。过滤器是可以设置为 16

位和 32 位两种模式的(即接收标准帧和拓展帧的区别)。这里可以 有根据我们想要接收的帧类型设置,在我们的例程中 16 位和 32 位 接收都有相应的函数,详细代码大家可以看例程。16
位模式设置为: CAN_FilterScale_16bit。32 位模式设置为:CAN_FilterScale_32bit。
    CAN_FilterIdHigh:这个是标示符寄存器的高 16 位。从介绍的图中, 我们可以看到 16 位的时候,标准 ID 的起始位置是从第 5 位开始的, 所以我们设置 ID
的时候要将 ID 左移 5 位。从第 5 位开始放起。而 在 32 位模式的时候,大家从图上可以看出 ID 是从 32 位寄存器的第
3 位开始放置的(在这里还有个知识点,就是拓展帧的结构,拓展帧 的结构并不是标准 ID11 位 + 28 位这样子的结构的,而是 28 位添加 的 ID 放在前面,接着 11 位标准 ID
放在后面这样子的)。所以我们 这里设置的时候,这里的高 16 位放置拓展帧是要右移 13 位,也就 是从拓展帧的第 13 位开始。
   CAN_FilterIdLow:这个是标示符寄存器的低 16 位。这里的设置跟 上面的高 16 位设置差不多。在 16 位模式下是一样的设置,而在 32 位模式下拓展帧左移 3 位在放置。
 CAN_FilterMaskIdHigh:这个是屏蔽寄存器高字节的设置,如果你想 要关心哪一位你就 ID 对应的位设置为 1。如果你要全部比较就全部 设置 ID 对应的位全部设置为
1。它的对应位置是跟标示符寄存器是 一样的。
 CAN_FilterMaskIdLow:这个是屏蔽寄存器高字节的设置,这个跟上 面的高字节设置是一样的。
    CAN_FilterFIFOAssignment:选择你要使用的邮箱,它有 0 和 1。我 们这里使用 0,所以设置为:CAN_Filter_FIFO0。
    CAN_FilterActivation:表示过滤器的使能。我们选择开启,设置为:
ENABLE。


7.    接收的话,如果要使用中断接收,我们要设置中断,也就是 NVIC,设 置方式我们应该很熟悉了,我们这里就不详细将了。代码如下: NVIC_InitTypeDef
NVIC_InitStructure;

/*  使能接收的中断和中断优先级 */ NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);

CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE); //FIFO0 消息挂号中断 允许.

25.5  例程函数
1.    CAN 初始化函数
/*****************************************************************

* Function Name   : CAN1_Config
* Description        :  初始化 CAN,波特率设置为 450K
* Input                   : mode:用来选择要使用的工作模式:主要有四种工作模
式:1、正常
*                                *  模式:CAN_Mode_Normal;2、CAN_Mode_Silent  :
静默模式;3、环
*                                *  回模式:CAN_Mode_LoopBack;4、静默环回模式:
CAN_Mode_Silent
*                                * _LoopBack。
* Output                  : None
* Return                  : None
*****************************************************************/


void CAN1_Config(uint8_t mode)
{

























GPIO_InitTypeDef GPIO_InitStructure; CAN_InitTypeDef CAN_InitStructure;

/*  初始化 IO 口 */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);


































GPIO_InitStructure.GPIO_Mode  =  GPIO_Mode_AF_PP;      //复用推挽输 出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;                //PA12
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;          //上拉输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;                //PA11


GPIO_Init(GPIOA, &GPIO_InitStructure);





















































/****************************************************************/
/****************** CAN 设置和初始化 ****************************/
/****************************************************************/

/*  打开时钟使能 */ RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);
/* 初始化 CAN 的参数 */ CAN_DeInit(CAN1);
CAN_StructInit(&CAN_InitStructure);

/* CAN  参数初始化 */
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;        //失能接收 FIFO 锁定模
式,新数据会覆盖旧数据
CAN_InitStructure.CAN_TXFP = DISABLE;        //优先级由报文标识符决


















CAN_InitStructure.CAN_Mode = mode;              //有普通模式和拓展模式
CAN_InitStructure.CAN_SJW  =  CAN_SJW_1tq;  //重新同步跳跃宽度  1





















个时间单位


/*  波特率设置,  当 APB1 的时钟频率是 36MHZ 的时候。 波特率的公式 为: */
/*   波 特 率 (Kpbs)   =   36M   /   ((CAN_BS1   +   CAN_BS2   +   1)   * CAN_Prescaler) */
CAN_InitStructure.CAN_BS1  = CAN_BS1_8tq;  //时间段 1  为 8  个时间 单位
CAN_InitStructure.CAN_BS2  = CAN_BS2_7tq;  //时间段 2  为 7  个时间 单位
CAN_InitStructure.CAN_Prescaler = 5; CAN_Init(CAN1, &CAN_InitStructure);
#ifdef CAN_RX0_INT_ENABLE CAN1_NVIC_Config();
#endif


}

2.    CAN 设置 16 位 ID 函数
/*****************************************************************
* Function Name    : CAN1_Config16BitFilter
* Description        :  设置 CAN 接收 16 两个标准 ID(设置 ID 位数全部相同才 能够通过)
* Input                   : id1:要接收的一个 ID
*                                * id2:要接收的一个 ID
* Output                  : None
* Return                  : None
****************************************************************/

void CAN1_Config16BitFilter(uint16_t id1, uint16_t id2)
{




CAN_FilterInitTypeDef   CAN_FilterInitStructure;
uint16_t mask = 0xFFFF;


/* CAN filter init  屏蔽寄存器初始化 */ CAN_FilterInitStructure.CAN_FilterNumber = 1;
//过滤
器 1
CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask;//ID
模式


/*  寄存器组设置为 16 位 */ CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_16bit;
CAN_FilterInitStructure.CAN_FilterIdHigh = (id1 << 5); //要接收的 ID
标示符 1
CAN_FilterInitStructure.CAN_FilterIdLow =   (id2 << 5); // 要 接 收 的
ID 标示符 2

/*  设置为所有 ID 位都要相同才接收 */ CAN_FilterInitStructure.CAN_FilterMaskIdHigh = (mask << 5); //MASK
CAN_FilterInitStructure.CAN_FilterMaskIdLow    = (mask << 5);
CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_Filter_FIFO0;
//FIFO0
CAN_FilterInitStructure.CAN_FilterActivation = ENABLE; //使能过滤器 1








































CAN_FilterInit(&CAN_FilterInitStructure);
}













































3.    CAN 发送函数
/*****************************************************************
* Function Name   : CAN1_SendMesg
* Description        :  发送一个报文
* Input                   : id:发送的 ID。
*                                * len:发送的数据长度(注意发送数据长度不能超过 8 个
字节)
*                                * dat:存放数据的指针
* Output                  : None
* Return                  : None
****************************************************************/


void CAN1_SendMesg(uint32_t id, uint8_t len, uint8_t *dat)
{



































































uint16_t i = 0;

CanTxMsg TxMessage;

/*  一次发送只能发送 8 个字节 */
if(len > 8)
{









return ;
}












/*  配置邮箱:设置标识符,数据长度和待发送数据 */ TxMessage.StdId = (id & 0x7FF); //标准帧 ID11 位
TxMessage.ExtId = (id >> 11);      //设置扩展标示符(拓展标示符有 29 位)
TxMessage.RTR  =  CAN_RTR_DATA;      //设置为数据帧(或远程帧为
CAN_RTR_Remote)
if((id & 0x7FF) == 0x7FF)             //检测是标准帧还是拓展帧(拓展帧大
于 11 位)
{
























TxMessage.IDE = CAN_ID_STD; //拓展 ID
}




























else
{































TxMessage.IDE = CAN_ID_EXT; //标准 ID
}


































TxMessage.DLC = len;                    //发送的数据长度

/*  将数据放入到邮箱中 */
for(i=0; i {










































TxMessage.Data[i] = *dat;
dat++;
}
















































/* 开始传送数据 */ CAN_Transmit(CAN1, &TxMessage);
}






















































4.    CAN 接收函数
/*****************************************************************
* Function Name    : CAN1_ReceiveMesg
* Description        :  接收一个报文
* Input                   : receiveBuff:接收数据的数组指针
* Output                  : None
* Return                  : None
****************************************************************/


void CAN1_ReceiveMesg(uint8_t *receiveBuff)

{
uint8_t i = 0;

CanRxMsg RxMessage;   //设置接收邮箱









if((CAN_MessagePending(CAN1, CAN_FIFO0) != 0)) //检查 FIFO0 里面是 否有数据
{














CAN_Receive(CAN1,CAN_FIFO0,&RxMessage); //读取 FIFO0 里面的 数据
for(i=0; i

















CAN_RXSBUF
{





















*receiveBuff = RxMessage.Data[i];
receiveBuff++;
}
}
}































5.    例程主函数
int main(void)
{



































uint8_t ledState, m, receiveId, i, canMode;

/*  初始化 */ TFT_Init(); FLASH_Init(); SYSTICK_Config(); USART1_Config(9600); LED_Config();
KEY_Config();

/*  彩屏显示初始化 */ GUI_DisplayInit();
m = 10;
canMode = 1; //要设置 canMode 不等于 CAN_SendData[10],以便进入循环 一开始就初始化
while(1)
{






























































/*  修改模式 */
if(canMode != CAN_SendData[10] )
{



































































canMode = CAN_SendData[10];
if(CAN_SendData[10])

{
CAN1_Config(CAN_Mode_Normal); Mode = (uint8_t *)CAN_ModeNormal;
}







else
{



}











CAN1_Config(CAN_Mode_LoopBack); Mode = (uint8_t *)CAN_ModeLoopBack;















CAN1_Config16BitFilter(CAN_SendData[9], 0x00);
}


















/*  如果接收 ID 改变,就重新设置接收 ID */
if(receiveId != CAN_SendData[9])
{























receiveId = CAN_SendData[9];
if(receiveId != 0x00)
{




























CAN1_Config16BitFilter(CAN_SendData[9], 0x00);
}
}


































/*  显示数据 */ GUI_DisplayData(m);
/* LED 灯闪烁 */
i++;
if(i > 0x5F)
{











































i = 0;
if(ledState == 0xFE)
{


















































}
else
{


}
















































ledState = 0xFF;





ledState = 0xFE;

























































LED_SetState(ledState);
}






























































/*  根据键盘,做出相应的操作 */
switch(KEY_Scan())
{



































































case(KEY_UP):
if(m == 10)
{
CAN_SendData[10] = ~CAN_SendData[10];
}
else
{


}
CAN_SendData[m]++;



GUI_Show12Char(175, 84, "等待发送", RED, BLACK);
break;
case(KEY_DOWN):


if(m == 10)
{














}
else
{


}













CAN_SendData[10] = ~CAN_SendData[10];





CAN_SendData[m]--;






















GUI_Show12Char(175, 84, "等待发送", RED, BLACK);
break;
case(KEY_LEFT):
if(m == 10)
{































}
else
{


}






























m = 0;





m++;







































break;
case(KEY_RIGHT):
CAN1_SendMesg(CAN_SendData[8], 8, CAN_SendData);//
发送数据
GUI_Show12Char(175, 84, "发送成功", BLUE, BLACK);
break;
default:
break;
}
}
}



专家
2015-12-11 09:39:56     打赏
2楼
从哪里copy来的,能否先排版一下?

院士
2015-12-11 11:31:36     打赏
3楼
看上去真心不错,我也做了一个类似的开发板。

菜鸟
2015-12-11 22:07:45     打赏
4楼
我的pdf中啊,有好几个图片没有copy过去。

助工
2015-12-30 16:58:19     打赏
5楼
楼主真心辛苦了

院士
2015-12-30 23:29:33     打赏
6楼
楼主的CAN通讯设计与本次STM32L053的试用活动无关哟~~故去掉了帖子的标签。

共6条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]