经过一段时间的学习,终于把CAN基本的东西给搞定,还有许多东西还要去学,在此先发一部分这段时间的学习内容,希望高手拍砖,让讨论抵御这大冷的冬天!!
在刚开始申请板子的时候是想采用232通信来完成电机的控制,但是拿到板子后发现该板子有好多资源,比如CAN,以太网啊,这些好东西。
本程序主要是参照TI公司的CAN例程,在里面修改;从这段时间的学习,我发现CAN功能很强,要比232要好,并且也方便,可以更好的利用好两个板子,所以就考虑用CAN来做电机控制。以前也没做过CAN方面的东西,所以这次很重视CAN的学习,论坛上也有好多高手写CAN方面的资料,下面还是有写罗嗦,望大家见谅。
不过这次例程是在前面的例程的基础上(通过按键实现直流电机的正反转和加减速!https://bbs.eeworld.com.cn/viewthread.php?tid=219790&highlight=%2Bfxw451)做了修改,直接用两个按键实现了电机的正反转,并且还考虑到在正反切换时很容易烧毁电机,在此做了一些改进,大家看看程序就明白了,很简单的。
控制直流电机转动的两个引脚为PWM0和PWM2,按键为Device板的UP和DOWN键。
下面主要介绍下CAN模块的实现:多罗嗦几句,也是必须罗嗦的部分。
应用流程:
一、对CAN的接受和发送设置理解
首先来谈一下对 历程中的CAN报文结构的理解
以下是我对一个报文结构的理解不知道对不对,初次接触CAN有错误的地方还望大家指点 一下
typedef struct
{
/*(1)*/ unsigned long ulMsgID; // 11或29位的CAN报文标识符 用于总线仲裁
/*(2)*/ unsigned long ulMsgIDMask; // 报文滤波器使能后的标识符掩码 用于多个.节点的杂通信 若个不使能报文滤波的话 这块可以不用管
/*(3)*/ unsigned long ulFlags; // 由tCANObjFlags列举的配置参数 此值保存多个 状态标志和 tCANObjFlags 所指定的设置 例如使能CAN接受中断以及报文滤波
可设 ulFlags=MSG_OBJ_RX_INT_ENABLE|MSG_OBJ_USE_ID_FILTER
多个状态设置或上就行
/*(4)*/ unsigned long ulMsgLen; // 报文数据域长度 指定报文数据场中数据的个. 数 最大8位 若是设置一个接受的报文对象缓冲区 这表示期望的数据宽度
/*(5)*/ unsigned char *pucMsgData; // 指向配置报文对象数据域数据的指针 即数据场中的数据地址
}tCANMsgObject;
对于CAN的启动
1.。在使用CAN前 先启动CAN 即置位INIT位 使用 CANInit(CAN0_BASE);
2.启动后设置位速CANBitRateSet(CAN0_BASE, 8000000, CAN_BITRATE);
3 使能CAN中断
4 为了接收一个特定的数据帧,要执行下列步骤:
(1) 把tMsgObjType 设置为MSG_OBJ_TYPE_RX。
(2) 把ulMsgID设为完整报文 ID,或使用部分 ID匹配的部分屏蔽。
(3) 设置ulMsgIDMask 位,用于在对比过程中的屏蔽。
(4) 按如下设置 ulFlags:
♦ 设置 MSG_OBJ_TX_INT_ENABLE 标志,以便在接收数据帧时被中断;
♦ 设置 MSG_OBJ_USE_ID_FILTER 标志,以便使能基于过滤的标识符。
ulFlags=MSG_OBJ_TX_INT_ENABLE|MSG_OBJ_USE_ID_FILTER
(5) 把ulMsgLen 设置为期望数据帧的字节数。
(6) 此次调用并不使用 pucMsgData 所指向的缓冲区。
(6 ) 调用CANMessageSet(unsigned long ulBase,
unsigned long ulObjID,
tCANMsgObject *pMsgObject,
tMsgObjType eMsgType) ,并把 ulObjID设置为 32 个对象缓冲区中的其中一个缓冲区。
如果您指定的报文对象缓冲区已包含有一个报文标识符,那么它将会被覆写。
5为了直接把一个数据帧或远程帧发送出去,要执行下列步骤:
(1) 把tMsgObjType 设置为MSG_OBJ_TYPE_TX。
(2) 把ulMsgID设为报文 ID。
(3) 设置ulFlags,设置 MSG_OBJ_TX_INT_ENABLE,以便在发送报文时获取一个中断。
为了禁止基于报文标识符的过滤,一定不要设置 MSG_OBJ_USE_ID_FILTER。
(4) 把ulMsgLen 设置为数据帧的字节数。
(5) 把pucMsgData 设置为指向一个包含报文字节的数组(如果是一个数据帧,不适用此
操作;如果是一个远程帧,把这设置为指向一个有效缓冲区则是一个好方法)。
(6) 调用CANMessageSet(unsigned long ulBase,
unsigned long ulObjID,
tCANMsgObject *pMsgObject,
tMsgObjType eMsgType) ,并把 ulObjID设置为 32 个对象缓冲区中的其中一个缓冲区。
二、通过系统时钟中断扫描键盘
在用can来控制开发版的PWM波时用到了按键在这里没有用GPIO中断来做用的是系统时中断。感觉历程中给的扫描程序写的相当的好 在这里我分享一下对断程序的理解
以前写键盘扫描程序的往往分两步1、用一个延时程序来 消斗 2、有一个while(1)来等待按键抬起。与历程给的相比这样做的话效率不高
历程中的程序用ulLastStatus 和 g_ulDebounceCounter 共同消斗 只有当ulDebounceCounter 等于4的时候才为可靠按下 如果出先按键状态和前一次不一样则清零ulDebounceCounter
用以下的两个if()语句判断按键 是刚被按下 还是以前起就一直被按下 g_ucButtonStatus为前一次扫描的按键状态 ulStatus 为本次扫描的按键状态
ucTemp = g_ucButtonStatus ^ ulStatus; 如果前一次状态为按下异或后ucTemp 对应位为0
if(ucTemp & GPIO_PIN_0) 判断 ucTemp 对应位的值
if(GPIO_PIN_0 & ulStatus) 判断按键是否是被按下
三、CAN中断的处理
1、进入CAN中断响应后用CANIntStatus(unsigned long ulBase, tCANIntStsReg eIntStsReg) 来读取CAN控制器当前中断状态 如果是一个报文中断则返回的是中中断报文的编号(1—32)利用返回的编号可以判断是接受数据中断 还是发送中断。
2、如果一个接收到的报文情况下使用CANMessageGet()读取报文 并清除报文对象中断。
3、如果是一个发送中断则用CANIntClear()来清除中断
4、如果两者都不是则使用 CANStatusGet()函数读取状态寄存器并清除状态中断
值得注意的事 对于中断的清除应在 处理程序的最后 以避免在真正清除中断源之前从中断处理程序中返回。 如果操作失败可会能导致立即再次进入中断处理程序。 (因为NVIC仍会把中断源看作是有效的)。
有错误之处还请高手指教,欢迎高手拍砖!!
——fxw451
2010.12.17
笔记内容:
(下载次数: 164, 2010-12-17 09:25 上传)
(下载次数: 148, 2010-12-17 09:25 上传)
CAN驱动资料:
(下载次数: 134, 2010-12-17 09:25 上传)
(下载次数: 133, 2010-12-17 09:25 上传)
控制直流电机转动的两个引脚为PWM0和PWM2,直流电机其实只有两个引线接可以了,在这里我用的是PWM0和PWM2。具体怎么实现他们的正反转和加减速的就是把一个引脚置低,另一个引脚设置占空比,就可以调速了,比如:我先把PWM0置0,调PWM2来实现电机的正转,通过调节PWM2的占空比来现在转速的调节,相反,我就可以实现电机的反转和加减速。
这个基于CAN的电机控制只是用到了两个按键,转速的调节和正反转是通过按键来实现的,如何实现的??其实很简单,我就是通过按键来显示一个数组的加减进而控制电机的正反转,有两个数组分别给PWM0和PWM2,
P0[]=[0.99,0.80,0.7,0.6,0.5,0.4,0.3,0.2,0.1,0,0,0,0,0,0,0,0,0,0,0],
P2[]=[0,0,0,0,0,0,0,0,0,0,0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.99]
21个数就可以实现了,比如我按下UP键,读取的是P0[0]和P2[0],分别给PWM0和PWM2,在按下UP键就是P0[1]和P2[1],以此类推,DOWN键其实就是减了,在这里我设置了P0[10]和P2[10]均为0,为了是怕电机在突然现在正反转的瞬间PWM0和PWM2都有电压,怕烧坏电机,加了个算是缓冲吧!!
非常感谢你提出了这么一个比较好的问题,在文档中没能说清楚,还请见谅!!
[ 本帖最后由 fxw451 于 2010-12-23 10:46 编辑 ]