CAN 是Controller Area Network的缩写(以下称为CAN),是ISO国际标准化的串行
通信协议。CAN 的高性能和可靠性被得到广泛的认可,并被应用于工业自动化、船舶、医疗设备、工业设备等方向,为分布式控制系统实现各节点之间实时、可靠的数据通信提供了强有力的技术支持。
MM32L073内置CAN模块,可以广泛应用于需要CAN通信的应用场景,具体以下特点:
- 支持 CAN 协议的 2.0 A 和 2.0 B
- 扩展的接收缓冲器 (64 字节、先进先出 FIFO)
- 同时支持 11 位和 29 位识别码
- 位速率可达 1Mbits/s
- 支持PeliCAN 模式扩展功能
- 支持硬件滤波器
AMetal已经完成了对MM32L073的适配,若用户选用AMetal平台,则无需自行适配,直接使用相应的CAN功能接口进行操作即可。
初始化
以CAN初始化函数为例,函数原型为:
am_can_handle_t am_mm32l073_can_inst_init(void);
该函数在user_config目录下的am_hwconf_mm32l073_can.c文件中定义为:
/** CAN 实例初始化,获得 CAN 标准服务句柄 */
am_can_handle_t am_mm32l073_can_inst_init(void)
{
return am_mm32l073_can_init(&__g_can_dev, &__g_can_devinfo);
}
在am_mm32l073_inst_init.h中声明为:
am_can_handle_t am_mm32l073_can_inst_init(void);
因此使用CAN初始化函数时,需要包含头文件am_mm32l073_inst_init.h。初始化CAN,调用该函数时需要定义一个am_can_handle_t类型的变量,用于保存获取的CAN服务句柄,CAN初始化程序为:
am_can_handle_t can_handle;
can_handle = am_mm32l073_can_inst_init();
接口函数
AMetal 提供了CAN相关的接口函数,详见表1。
函数原型
| 功能简介
|
am_can_start (am_can_handle_t handle);
| 启动CAN通信
|
am_can_reset (am_can_handle_t handle);
| 复位CAN通信
|
am_can_sleep (am_can_handle_t handle);
| CAN睡眠
|
am_can_wakeup (am_can_handle_t handle);
| CAN唤醒
|
am_can_int_enable (am_can_handle_t handle,am_can_int_type_t mask);
| CAN中断使能
|
am_can_int_disable (am_can_handle_t handle,
am_can_int_type_t mask);
| CAN中断禁能
|
am_can_mode_set ( am_can_handle_t handle,
am_can_mode_type_t mode)
| CAN工作模式设置
|
am_can_baudrate_set (am_can_handle_t handle,
struct am_can_bps_param *p_can_baudrate)
| CAN波特率设置
|
am_can_baudrate_get (am_can_handle_t handle,
struct am_can_bps_param *p_can_baudrate)
| CAN波特率获取
|
am_can_err_cnt_get ( am_can_handle_t handle,
struct am_can_err_cnt *p_can_err_cnt)
| CAN获取错误计数
|
am_can_err_cnt_clr (am_can_handle_t handle);
| CAN清除错误计数
|
am_can_msg_send ( am_can_handle_t handle,
am_can_message_t *p_txmsg)
| CAN发送消息
|
am_can_msg_recv (am_can_handle_t handle,
am_can_message_t *p_rxmsg)
| CAN接收消息
|
am_can_msg_stop_send(am_can_handle_t handle);
| CAN停止发送
|
am_can_filter_tab_set (am_can_handle_t handle,
uint8_t *p_filterbuff,
size_t lenth)
| CAN设置滤波
|
am_can_filter_tab_get (am_can_handle_t handle,
uint8_t *p_filterbuff,
size_t *p_lenth)
| CAN获取滤波设置
|
am_can_status_get ( am_can_handle_t handle,
am_can_int_type_t *p_int_type,
am_can_bus_err_t *p_bus_err)
| CAN状态获取
|
am_can_connect ( am_can_handle_t handle,
am_pfnvoid_t pfn_isr,
void *p_arg)
| CAN中断连接
|
am_can_disconnect ( am_can_handle_t handle,
am_pfnvoid_t pfn_isr,
void *p_arg)
| CAN删除中断连接
|
am_can_intcb_connect ( am_can_handle_t handle,
am_can_int_type_t inttype,
am_pfnvoid_t pfn_callback,
void *p_arg)
| CAN注册中断回调函数
|
am_can_intcb_disconnect ( am_can_handle_t handle,
am_can_int_type_t inttype)
| CAN解除中断回调的注册
|
表 1 CAN 接口函数
1. CAN 通信启动
CAN 通信完成初始化之后,调用启动 CAN 通信函数开始通信,函数原型为:am_can_err_t am_can_start (am_can_handle_t handle)
- handle 为 CAN 的服务句柄,即为初始化 CAN 获取的句柄;
- 返回值为 AM_CAN_NOERROR,设置成功;
- 返回值为-AM_CAN_INVALID_PARAMETER 则设置失败,参数错误;
2. CAN 通信复位
复位 CAN 通信,函数原型为:am_can_err_t am_can_reset (am_can_handle_t handle)
- handle 为 CAN 的服务句柄,即为初始化 CAN 获取的句柄;
- 返回值为 AM_CAN_NOERROR,设置成功;
- 返回值为-AM_CAN_INVALID_PARAMETER 则设置失败,参数错误;
3. CAN 通信睡眠
CAN 通信睡眠的函数原型为:
am_can_err_t am_can_sleep (am_can_handle_t handle)
- handle 为 CAN 的服务句柄,即为初始化 CAN 获取的句柄;
- 返回值为 AM_CAN_NOERROR,设置成功;
- 返回值为-AM_CAN_INVALID_PARAMETER 则设置失败,参数错误;
4. CAN 通信唤醒
CAN 通信唤醒的函数原型为:
am_can_err_t am_can_wakeup (am_can_handle_t handle)
- handle 为 CAN 的服务句柄,即为初始化 CAN 获取的句柄;
- 返回值为 AM_CAN_NOERROR, 唤醒成功;
- 返回值为-AM_CAN_INVALID_PARAMETER 则唤醒失败,参数错误;
5. CAN 中断使能
CAN 中断使能的函数原型为:
am_can_err_t am_can_int_enable (am_can_handle_t handle, am_can_int_type_t mask)
- handle 为 CAN 的服务句柄,即为初始化 CAN 获取的句柄;
- mask 为中断类型;
- 返回值为 AM_CAN_NOERROR,设置成功;
- 返回值为-AM_CAN_INVALID_PARAMETER 则设置失败,参数错误;
AMetal 中定义了 CAN 的中断类型, 详见表2。
CAN 中断类型宏
| 功能说明
|
AM_CAN_INT_NONE
| 无类型中断
|
AM_CAN_INT_ERROR
| 错误中断
|
AM_CAN_INT_BUS_OFF
| 总线关闭中断
|
AM_CAN_INT_WAKE_UP
| 唤醒中断
|
AM_CAN_INT_TX
| 发送中断
|
AM_CAN_INT_RX
| 接收中断
|
AM_CAN_INT_DATAOVER
| 总线超载中断
|
AM_CAN_INT_WARN
| 警告中断
|
AM_CAN_INT_ERROR_PASSIVE
| 错误被动中断
|
AM_CAN_INT_ALL
| 所有中断
|
表 2 中断类型说明
6. CAN 中断禁能
CAN 中断禁能的函数原型为:am_can_err_t am_can_int_disable (am_can_handle_t handle, am_can_int_type_t mask)
- handle 为 CAN 的服务句柄,即为初始化 CAN 获取的句柄;
- mask 为中断类型;
- 返回值为 AM_CAN_NOERROR,设置成功;
- 返回值为-AM_CAN_INVALID_PARAMETER 则设置失败,参数错误;
AMetal 中定义了 CAN 的中断类型, 详见表2。
7. CAN 设置模式
CAN 工作模式设置的函数原型为:
am_can_err_t am_can_mode_set (am_can_handle_t handle,
am_can_mode_type_t mode)
- handle 为 CAN 的服务句柄,即为初始化 CAN 获取的句柄;
- mode 为工作模式;
- 返回值为 AM_CAN_NOERROR,设置成功;
- 返回值为-AM_CAN_INVALID_PARAMETER 则设置失败,参数错误;
AMetal 中定义了 CAN 的工作模式,详见表3。
CAN 工作模式宏说明
| 模式说明
|
AM_CAN_MODE_NROMAL
| 正常工作模式
|
AM_CAN_MODE_LISTEN_ONLY
| 只听工作模式
|
表 3 CAN 工作模式说明
8. CAN 设置波特率
CAN 波特率设置的函数原型为:
am_can_err_t am_can_baudrate_set (am_can_handle_t handle,
struct am_can_bps_param *p_can_baudrate)
- handle 为 CAN 的服务句柄,即为初始化 CAN 获取的句柄;
- p_can_baudrate 为波特率结构体指针;
- 返回值为 AM_CAN_NOERROR,设置成功;
- 返回值为-AM_CAN_INVALID_PARAMETER 则设置失败,参数错误;
9. CAN 获取波特率
CAN 波特率获取的函数原型为:
am_can_err_t am_can_baudrate_get (am_can_handle_t struct handle,
am_can_bps_param *p_can_baudrate)
- handle为CAN的服务句柄,即为初始化CAN获取的句柄;
- p_can_baudrate为波特率结构体指针;
- 返回值为 AM_CAN_NOERROR,获取成功;
- 返回值为-AM_CAN_INVALID_PARAMETER 则获取失败,参数错误;
10. CAN 获取错误计数
CAN 获取错误计数的函数原型为:
am_can_err_t am_can_err_cnt_get ( am_can_handle_t handle,
struct am_can_err_cnt *p_can_err_cnt)
- handle为CAN的服务句柄,即为初始化CAN获取的句柄;
- p_can_err_cnt为错误计数的结构体指针;
- 返回值为 AM_CAN_NOERROR,获取成功;
- 返回值为-AM_CAN_INVALID_PARAMETER 则获取失败,参数错误;
11. CAN 清空错误计数
CAN 清空错误计数的函数原型为:
am_can_err_t am_can_err_cnt_clr (am_can_handle_t handle)
- handle 为 CAN 的服务句柄,即为初始化 CAN 获取的句柄;
- 返回值为 AM_CAN_NOERROR, 清空成功;
- 返回值为-AM_CAN_INVALID_PARAMETER则清空失败,参数错误;
12. CAN发送消息
CAN发送消息的函数原型为:
am_can_err_t am_can_msg_send(am_can_handle_t handle,
am_can_message_t *p_txmsg)
- handle为CAN的服务句柄,即为初始化CAN获取的句柄;
- p_txmsg为发送消息的结构体指针;
- 返回值为AM_CAN_NOERROR,发送成功;
- 返回值为-AM_CAN_INVALID_PARAMETER则发送失败,参数错误;
13. CAN接收消息
CAN接收消息的函数原型为:am_can_err_t am_can_msg_recv(am_can_handle_t handle,
am_can_message_t *p_rxmsg)
- handle为CAN的服务句柄,即为初始化CAN获取的句柄;
- p_rxmsg为发送消息的结构体指针;
- 返回值为AM_CAN_NOERROR,接收成功;
- 返回值为-AM_CAN_INVALID_PARAMETER则接收失败,参数错误;
14. CAN停止发送消息
CAN停止发送消息的函数原型为:
am_can_err_t am_can_msg_stop_send(am_can_handle_t handle)
- handle为CAN的服务句柄,即为初始化CAN获取的句柄;
- 返回值为AM_CAN_NOERROR,设置成功;
- 返回值为-AM_CAN_INVALID_PARAMETER则设置失败,参数错误;
15. CAN设置滤波
CAN设置滤波的函数原型为:am_can_err_t am_can_filter_tab_set (am_can_handle_t handle,
uint8_t *p_filterbuff,
size_t lenth)
- handle为CAN的服务句柄,即为初始化CAN获取的句柄;
- p_filterbuff为滤波表的首地址;
- lenth为滤波表长度;
- 返回值为AM_CAN_NOERROR,设置成功;
- 返回值为-AM_CAN_INVALID_PARAMETER则设置失败,参数错误;
16. CAN获取设置滤波
CAN获取设置滤波的函数原型为:
am_can_err_t am_can_filter_tab_get (am_can_handle_t handle,
uint8_t *p_filterbuff,
size_t *p_lenth)
- handle为CAN的服务句柄,即为初始化CAN获取的句柄;
- p_filterbuff为滤波表的首地址;
- lenth为滤波表长度;
- 返回值为AM_CAN_NOERROR,获取成功;
- 返回值为-AM_CAN_INVALID_PARAMETER则获取失败,参数错误;
17. CAN状态获取
CAN获取状态的函数原型为:am_can_err_t am_can_status_get (am_can_handle_t handle,
am_can_int_type_t *p_int_type,
am_can_bus_err_t *p_bus_err)
- handle为CAN的服务句柄,即为初始化CAN获取的句柄;
- p_int_type为中断类型;
- p_bus_err为总线错误类型;
- 返回值为AM_CAN_NOERROR,获取成功;
- 返回值为-AM_CAN_INVALID_PARAMETER则获取失败,参数错误;
18. CAN中断连接
CAN中断连接的函数原型为:
am_can_err_t am_can_connect (am_can_handle_t handle,
am_pfnvoid_t pfn_isr,
void *p_arg)
- handle为CAN的服务句柄,即为初始化CAN获取的句柄;
- pfn_isr为中断服务函数;
- p_arg为中断服务参数;
- 返回值为AM_CAN_NOERROR,设置成功;
- 返回值为-AM_CAN_INVALID_PARAMETER则设置失败,参数错误;
19. CAN删除中断连接
CAN删除中断连接的函数原型为:
am_can_err_t am_can_disconnect (am_can_handle_t handle,
am_pfnvoid_t pfn_isr,
void *p_arg)
- handle为CAN的服务句柄,即为初始化CAN获取的句柄;
- pfn_isr为中断服务函数;
- p_arg为中断服务参数;
- 返回值为AM_CAN_NOERROR,设置成功;
- 返回值为-AM_CAN_INVALID_PARAMETER则设置失败,参数错误;
20. CAN注册中断回调函数
CAN注册中断回调函数的原型为:
am_can_err_t am_can_intcb_connect (am_can_handle_t handle,
am_can_int_type_t inttype,
am_pfnvoid_t pfn_callback,
void *p_arg)
- handle为CAN的服务句柄,即为初始化CAN获取的句柄;
- inttype为中断类型;
- pfn_callback为中断回调函数;
- p_arg为回调函数参数;
- 返回值为AM_CAN_NOERROR,设置成功;
- 返回值为-AM_CAN_INVALID_PARAMETER则设置失败,参数错误;
21. CAN解除中断回调函数的注册
CAN解除中断回调函数注册的函数原型为:
am_can_err_t am_can_intcb_connect (am_can_handle_t handle,
am_can_int_type_t inttype,
am_pfnvoid_t pfn_callback,
void *p_arg)
- handle为CAN的服务句柄,即为初始化CAN获取的句柄;
- inttype为中断类型;
- 返回值为AM_CAN_NOERROR,设置成功;
- 返回值为-AM_CAN_INVALID_PARAMETER则设置失败,参数错误;
应用实例
本例将演示一个CAN通信的示例,需要通过USB转CAN连接到PC端,借助USB转CAN的上位机来演示收发过程。为了便于观察,可以通过串口观察收到的数据,实现代码如下:
#include "ametal.h"
#include "am_can.h"
#include "am_delay.h"
#include "am_vdebug.h"
#include "amhw_mm32l073_can.h"
#include "am_mm32l073_can.h"
/* 滤波表 */
sta
tic uint8_t table[8] = {0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x01, 0xc0};
/* 错误判断*/
static void __can_err_sta(am_can_bus_err_t err)
{
if (err & AM_CAN_BUS_ERR_BIT)
{ /* 位错误 */
am_kprintf(("AM_CAN_BUS_ERR_BITn"));
}
if (err &AM_CAN_BUS_ERR_ACK)
{ /* 应答错误 */
am_kprintf(("AM_CAN_BUS_ERR_ACKn"));
}
if (err &AM_CAN_BUS_ERR_CRC)
{ /* CRC 错误 */
am_kprintf(("AM_CAN_BUS_ERR_CRCn"));
}
if (err &AM_CAN_BUS_ERR_FORM)
{ /* 格式错误 */
am_kprintf(("AM_CAN_BUS_ERR_FORMn"));
}
if (err &AM_CAN_BUS_ERR_STUFF)
{ /* 填充错误 */
am_kprintf(("AM_CAN_BUS_ERR_STUFFn"));
}
}
/* 例程入口 */
void demo_mm32l073_can_entry (am_can_handle_t can_handle,
am_can_bps_param_t *can_btr_baud)
{
am_can_err_t ret;
uint8_t i = 0;
am_can_message_t can_rcv_msg = {0};
am_can_bus_err_t can_bus_err_status;
am_can_int_type_t can_int_status;
/* 配置波特率 */
ret =am_can_baudrate_set (can_handle, can_btr_baud); //设置 CAN 波特率
if (ret == AM_CAN_NOERROR)
{
am_kprintf("rnCAN: controller baudrate set ok. rn");
}
else
{
am_kprintf("rnCAN: controller baudrate set error! %d rn", ret);
}
/* 配置滤波表 */
ret =am_can_filter_tab_set( can_handle,table,sizeof(table)/sizeof(uint8_t));
if (ret == AM_CAN_NOERROR)
{
am_kprintf("rnCAN: controller filter tab set ok. rn");
}
else
{
am_kprintf("rnCAN: controller filter tab set error! %d rn", ret);
}
/* 启动 can */
ret =am_can_start (can_handle);
if (ret == AM_CAN_NOERROR)
{
am_kprintf("rnCAN: controller start rn");
}
else
{
am_kprintf("rnCAN: controller start error! %d rn", ret);
}
AM_FOREVER {
ret =am_can_msg_recv (can_handle, &can_rcv_msg); //接收数据
if (can_rcv_msg.msglen || can_rcv_msg.flags || can_rcv_msg.id)
{ //校验ID
am_kprintf("can recv id: 0x%xrn",can_rcv_msg.id);
for (i = 0; i < can_rcv_msg.msglen; i++)
{
am_kprintf("data: 0x%x rn",can_rcv_msg.msgdata
);
}
ret =am_can_msg_send (can_handle, &can_rcv_msg); //数据发送
if (ret == AM_CAN_NOERROR)
{
am_kprintf(("rnCAN: controller rcv data ok. rn"));
}
else
{
am_kprintf("rnCAN: controller no rcv data! rn");
}
}
ret =am_can_status_get (can_handle, //获取 CAN 通信状态
&can_int_status,
&can_bus_err_status);
am_mdelay(10);
if (can_bus_err_status != AM_CAN_BUS_ERR_NONE)
{
__can_err_sta(can_bus_err_status);
}
}
}