1.CAN通信原理介绍:
1.1 CAN介绍:
1.CAN(Controller Area Network)是二十世纪八十年代初德国Bosch公司为解决现代汽车中众多电控单元(ECU)之间的数据交换而开发的一种多主机局部网络串行通信协议。
2.是一种串行通信协议,能有效的支持具有很高安全等级的分布实时控制。
3.应用范围很广,数据传输速度极快,较为稳定。
2.CAN通信协议:
2.1 CAN协议:
1.CAN总线上传输的信息称为报文,当总线空闲时任何连接的单元都可以开始发送新的报文。
2. CAN通信是通过以下5种类型的帧进行的:数据帧、遥控帧、错误帧、过载帧、帧间隔。
3. CAN协议节点
3.硬件介绍:
STM32F405RGT6MCU开发板:进行程序编写,以及电机的控制。
USBCAN-II CS收发器:当CAN监听功能,查看数据传输是否正确。
EUC3100 USB-485转换器:串口数发送。
CAN电路设计:
CAN电路
RS485电路设计:
RS485电路
USBCAN-II CS收发器 USB-485转换器
4.软件介绍:
软件介绍:STM32CubeMx软件:STM32单片机端的软件开发环境采用STM32CubeMX软件,并配合使用Keil MDK5,通过C语言编程。
1.打开STM32CubeMx,新建项目
2.输入自己使用的芯片,双击
3.配置好RCC,与SYS。
4.配置好CAN1
1.选择CAN,勾选Activated
2.Bit Timings Parameters中Prescaler改为9,Bit1 改为5Times,Bit2 改为2Times ,Jump Width 改为1Times .(波特率计算公式:36M/9/(5+2+1)=500K.)
3.使能CAN RX0中断,代表的是接受邮箱0的接收中断
5.设置串口:
1.打开串口异步通信
2.波特率按要求设定,使能中断Enabled勾上;
6.设置主频并输出。
5.代码部分:
共为四个部分:CAN滤波器;CAN接收,CAN发送;电机控制程序;串口部分。
1. CAN滤波器:
CAN_TxHeaderTypeDef can1_tx_header_msg;
CAN_RxHeaderTypeDef can1_rx_header_msg;
CAN_RecvMsg can1_recv_msg;
CAN_RecvMsg can2_recv_msg;
void can1_cfg_init(void)
{
CAN_FilterTypeDef sFilterConfig;
sFilterConfig.FilterIdHigh = 0x0000;
sFilterConfig.FilterIdLow = 0x0000;
sFilterConfig.FilterMaskIdHigh = 0x0000;
sFilterConfig.FilterMaskIdLow = 0x0000;
sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0;
sFilterConfig.FilterBank = 0;
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
sFilterConfig.FilterActivation = ENABLE;
sFilterConfig.SlaveStartFilterBank = 14;
if (HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK)
{
Error_Handler();
}
if (HAL_CAN_Start(&hcan1) != HAL_OK)
{
Error_Handler();
}
if (HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK)
{
Error_Handler();
}
}
2. CAN接收,CAN发送
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
if (hcan->Instance == CAN1)
{
HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &can1_rx_header_msg, can1_recv_msg.data);
}
}
void can1_transmit(uint16_t std_id, uint8_t *buff)
{
can1_tx_header_msg.DLC = 5;
can1_tx_header_msg.StdId = std_id;
can1_tx_header_msg.ExtId = 0;
can1_tx_header_msg.IDE = CAN_ID_STD;
can1_tx_header_msg.RTR = CAN_RTR_DATA;
if (HAL_CAN_AddTxMessage(&hcan1, &can1_tx_header_msg, buff, (uint32_t *)CAN_TX_MAILBOX0) != HAL_OK)
{
Error_Handler();
}
}
3.电机控制程序:
#define MOTOR1_IDD 0x01
uint32_t ret1=0;
uint32_t ret2=0; uint32_t ress; uint32_t ressS;
/*************************设置电机模式*********************************************/
int32_t set_work_mode(yz_motor_tt motor_id, motor_work_mode_tt mode,int32_t val)
{
uint16_t i = 0xffff;
uint16_t res;
uint8_t buff[5] = {0x1D,0x00,0x00,0x00,0x00};
buff[1] = (uint8_t)(val & 0x000000ff);
buff[2] = (uint8_t)((val & 0x0000ff00) >> 8);
buff[3] = (uint8_t)((val & 0x00ff0000) >> 16);
buff[4] = (uint8_t)((val & 0xff000000) >> 24);
ress=(uint32_t)(buff[1] + (buff[2] << 8) + (buff[3] << 16) + (buff[4] << 24));
if (motor_id == YZ_MOTORR_0)
{
can1_transmit(MOTOR1_IDD, (uint8_t *)buff);
}
while (1)
{
i--;
if (i == 0)
{
break;
}
if (motor_id == YZ_MOTORR_0)
{
if ((can1_recv_msg.data)[0] == 0x00 || (can1_recv_msg.data)[0] == 0x01 || (can1_recv_msg.data)[0] == 0x02 || (can1_recv_msg.data)[0] == 0x03)
{
return res = (can1_recv_msg.data)[1] + ((can1_recv_msg.data)[2] << 8) + ((can1_recv_msg.data)[3] << 16) + ((can1_recv_msg.data)[4] << 24);
}
}
}
return res;
}
/**
* @brief 获取运行状态
* @param motor_id: 电机的名称
* @retval 状态值
*/
int32_t get_state_word(yz_motor_tt motor_id)
{
uint16_t i = 0xffff;
uint16_t res;
uint8_t buff[1] = {0x03};
if (motor_id == YZ_MOTORR_0)
{
can1_transmit1(MOTOR1_IDD, (uint8_t *)buff);
}
// 一直读取
while (1)
{
i--;
if (i == 0)
{
break;
}
if (motor_id == YZ_MOTORR_0)
{
if ((can1_recv_msg.data)[0] == 0x00 || (can1_recv_msg.data)[0] == 0x01 || (can1_recv_msg.data)[0] == 0x02 || (can1_recv_msg.data)[0] == 0x03)
{
return res = (can1_recv_msg.data)[0];
}
}
}
return res;
}
/*************************设置波特率*********************************************/
int32_t set_bit(yz_motor_tt motor_id,int32_t val)
{
uint16_t i = 0xffff;
uint16_t res;
uint8_t buff[5] = {0x3F,0x00,0x00,0x00,0x00};
buff[1] = (uint8_t)(val & 0x000000ff);
buff[2] = (uint8_t)((val & 0x0000ff00) >> 8);
buff[3] = (uint8_t)((val & 0x00ff0000) >> 16);
buff[4] = (uint8_t)((val & 0xff000000) >> 24);
ressS=(uint32_t)(buff[1] + (buff[2] << 8) + (buff[3] << 16) + (buff[4] << 24));
if (motor_id == YZ_MOTORR_0)
{
can1_transmit(MOTOR1_IDD, (uint8_t *)buff);
}
while (1)
{
i--;
if (i == 0)
{
break;
}
if (motor_id == YZ_MOTORR_0)
{
if ((can1_recv_msg.data)[0] == 0x00 || (can1_recv_msg.data)[0] == 0x01 || (can1_recv_msg.data)[0] == 0x02 || (can1_recv_msg.data)[0] == 0x03)
{
return res = (can1_recv_msg.data)[1] + ((can1_recv_msg.data)[2] << 8) + ((can1_recv_msg.data)[3] << 16) + ((can1_recv_msg.data)[4] << 24);
}
}
}
return res;
}
/****************初始化设置*******************/
void my_motor(void)
{
set_work_mode(YZ_MOTORR_0,SPEED_MODEE,1000);
HAL_Delay(1000);
}
4.串口部分:
printf重定义:
1.在usart.c最下面添加以下函数
/*********************************************************
*
*重定义 fputc 函数
*
**********************************************************/
int fputc(int ch,FILE *f)
{
HAL_UART_Transmit (&huart6 ,(uint8_t *)&ch,1,HAL_MAX_DELAY );
return ch;
}
2.在usart.c中添加头文件:#include "stdio.h"
3.魔法棒打开,然后将Use MicroLlB勾上
4.在main.c文件中添加头文件:#include <string.h> #include <stdio.h>
5.main
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_CAN1_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
can1_cfg_init();
HAL_UART_Receive_IT(&huart1, &rx_buffer, 1);//放串口初始化后面
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_11,GPIO_PIN_RESET);
my_motor();
RS485_SentMode();
printf("zhuangtai11:%d \r\n ",ret1);
printf("zhuangtai22:%d \r\n ",ret2);
RS485_ResMode();
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
6.CAN分析仪与串口调试:
7.总结:
基于STM32(HAL库)的CAN通信驱动伺服电机,使用电机的通信协议,使用CAN数据发送。
有错误等问题,及时联系我,谢谢!