ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

STM32F103C8T6测试USB-CAN模块

STM32F103C8T6测试USB-CAN模块 main.c#include led.h #include delay.h #include key.h #include sys.h #include lcd.h #include usart.h #include can.h #define MOTOR_ID 1 int main(void) { //电机MIT变量 float target_pos 0.0f; float target_vel 8.0f; float kp_val 0.0f; float kd_val 1.5f; float ff_torque 0.0f; int tk 0; u8 key; u8 i0,t0; u8 cnt0; u8 canbuf[8]{0x80,0x00,0x9C,0x70 ,0x00 ,0x33 ,0x38, 0x00}; u8 stopbuf[8]{0x80,0x00,0x80,0x00, 0x00,0x00,0x08,0x00}; u8 res; u8 modeCAN_Mode_LoopBack;//CAN工作模式;CAN_Mode_Normal(0)普通模式CAN_Mode_LoopBack(1)环回模式 delay_init(); //延时函数初始化 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组22位抢占优先级2位响应优先级 uart_init(100000); CAN_Mode_Init(CAN_SJW_1tq,CAN_BS2_2tq,CAN_BS1_3tq,6,CAN_Mode_Normal);//CAN初始化环回模式,波特率1Mbps 36M/((123)*6) //发送0xFC切换电机运行模式使能 res Can_Send_ModeFrame(MOTOR_ID,0xFC); delay_ms(1000); while(1) { target_vel 8; pack_command_frame(canbuf,target_pos,target_vel,kp_val,kd_val,ff_torque); Can_Send_Msg_Id(MOTOR_ID, canbuf, 8); delay_ms(500); } }can.h#ifndef __CAN_H #define __CAN_H #include sys.h //CAN接收RX0中断使能 #define CAN_RX0_INT_ENABLE 0 //0,不使能;1,使能. u8 CAN_Mode_Init(u8 tsjw,u8 tbs2,u8 tbs1,u16 brp,u8 mode);//CAN初始化 u8 Can_Send_Msg(u8* msg,u8 len); //发送数据 u8 Can_Receive_Msg(u8 *buf); //接收数据 int float_to_uint(float x, float x_min, float x_max, int bits); float uint_to_float(int x_int, float x_min, float x_max, int bits); void pack_command_frame(uint8_t *data, float p_des, float v_des, float Kp, float Kd, float tff); void unpack_command_frame(uint8_t* data, float *commands); u8 Can_Send_ModeFrame(uint8_t motor_id,uint8_t cmd_code); u8 Can_Send_Msg_Id(uint16_t stdid,u8* msg,u8 len); #endifcan.c#include can.h #include led.h #include delay.h #include usart.h //CAN初始化 //tsjw:重新同步跳跃时间单元.范围:CAN_SJW_1tq~ CAN_SJW_4tq //tbs2:时间段2的时间单元. 范围:CAN_BS2_1tq~CAN_BS2_8tq; //tbs1:时间段1的时间单元. 范围:CAN_BS1_1tq ~CAN_BS1_16tq //brp :波特率分频器.范围:1~1024; tq(brp)*tpclk1 //波特率Fpclk1/((tbs11tbs211)*brp); //mode:CAN_Mode_Normal,普通模式;CAN_Mode_LoopBack,回环模式; //Fpclk1的时钟在初始化的时候设置为36M,如果设置CAN_Mode_Init(CAN_SJW_1tq,CAN_BS2_8tq,CAN_BS1_9tq,4,CAN_Mode_LoopBack); //则波特率为:36M/((891)*4)500Kbps //返回值:0,初始化OK; // 其他,初始化失败; u8 CAN_Mode_Init(u8 tsjw,u8 tbs2,u8 tbs1,u16 brp,u8 mode) { GPIO_InitTypeDef GPIO_InitStructure; CAN_InitTypeDef CAN_InitStructure; CAN_FilterInitTypeDef CAN_FilterInitStructure; #if CAN_RX0_INT_ENABLE NVIC_InitTypeDef NVIC_InitStructure; #endif RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//使能PORTA时钟 RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);//使能CAN1时钟 GPIO_InitStructure.GPIO_Pin GPIO_Pin_12; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF_PP; //复用推挽 GPIO_Init(GPIOA, GPIO_InitStructure); //初始化IO GPIO_InitStructure.GPIO_Pin GPIO_Pin_11; GPIO_InitStructure.GPIO_Mode GPIO_Mode_IPU; //上拉输入 GPIO_Init(GPIOA, GPIO_InitStructure); //初始化IO //CAN单元设置 CAN_InitStructure.CAN_TTCMDISABLE; //非时间触发通信模式 CAN_InitStructure.CAN_ABOMDISABLE; //软件自动离线管理 CAN_InitStructure.CAN_AWUMDISABLE; //睡眠模式通过软件唤醒(清除CAN-MCR的SLEEP位) CAN_InitStructure.CAN_NARTENABLE; //禁止报文自动传送 CAN_InitStructure.CAN_RFLMDISABLE; //报文不锁定,新的覆盖旧的 CAN_InitStructure.CAN_TXFPDISABLE; //优先级由报文标识符决定 CAN_InitStructure.CAN_Mode mode; //模式设置 mode:0,普通模式;1,回环模式; //设置波特率 CAN_InitStructure.CAN_SJWtsjw; //重新同步跳跃宽度(Tsjw)为tsjw1个时间单位 CAN_SJW_1tq CAN_SJW_2tq CAN_SJW_3tq CAN_SJW_4tq CAN_InitStructure.CAN_BS1tbs1; //Tbs1tbs11个时间单位CAN_BS1_1tq ~CAN_BS1_16tq CAN_InitStructure.CAN_BS2tbs2; //Tbs2tbs21个时间单位CAN_BS2_1tq ~ CAN_BS2_8tq CAN_InitStructure.CAN_Prescalerbrp; //分频系数(Fdiv)为brp1 CAN_Init(CAN1, CAN_InitStructure); //初始化CAN1 CAN_FilterInitStructure.CAN_FilterNumber0; //过滤器0 CAN_FilterInitStructure.CAN_FilterModeCAN_FilterMode_IdMask; //屏蔽位模式 CAN_FilterInitStructure.CAN_FilterScaleCAN_FilterScale_32bit; //32位宽 CAN_FilterInitStructure.CAN_FilterIdHigh0x0000; //32位ID CAN_FilterInitStructure.CAN_FilterIdLow0x0000; CAN_FilterInitStructure.CAN_FilterMaskIdHigh0x0000;//32位MASK CAN_FilterInitStructure.CAN_FilterMaskIdLow0x0000; CAN_FilterInitStructure.CAN_FilterFIFOAssignmentCAN_Filter_FIFO0;//过滤器0关联到FIFO0 CAN_FilterInitStructure.CAN_FilterActivationENABLE;//激活过滤器0 CAN_FilterInit(CAN_FilterInitStructure); //滤波器初始化 #if CAN_RX0_INT_ENABLE CAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE); //FIFO0消息挂号中断允许. NVIC_InitStructure.NVIC_IRQChannel USB_LP_CAN1_RX0_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority 1; // 主优先级为1 NVIC_InitStructure.NVIC_IRQChannelSubPriority 0; // 次优先级为0 NVIC_InitStructure.NVIC_IRQChannelCmd ENABLE; NVIC_Init(NVIC_InitStructure); #endif return 0; } #if CAN_RX0_INT_ENABLE //使能RX0中断 //中断服务函数 void USB_LP_CAN1_RX0_IRQHandler(void) { CanRxMsg RxMessage; int i0; CAN_Receive(CAN1, 0, RxMessage); for(i0;i8;i) printf(rxbuf[%d]:%d\r\n,i,RxMessage.Data[i]); } #endif //can发送一组数据(固定格式:ID为0X12,标准帧,数据帧) //len:数据长度(最大为8) //msg:数据指针,最大为8个字节. //返回值:0,成功; // 其他,失败; u8 Can_Send_Msg(u8* msg,u8 len) { u8 mbox; u16 i0; CanTxMsg TxMessage; TxMessage.StdId0x12; // 标准标识符 TxMessage.ExtId0x12; // 设置扩展标示符 TxMessage.IDECAN_Id_Standard; // 标准帧 TxMessage.RTRCAN_RTR_Data; // 数据帧 TxMessage.DLClen; // 要发送的数据长度 for(i0;ilen;i) TxMessage.Data[i]msg[i]; mbox CAN_Transmit(CAN1, TxMessage); i0; while((CAN_TransmitStatus(CAN1, mbox)CAN_TxStatus_Failed)(i0XFFF))i; //等待发送结束 if(i0XFFF)return 1; return 0; } //can口接收数据查询 //buf:数据缓存区; //返回值:0,无数据被收到; // 其他,接收的数据长度; u8 Can_Receive_Msg(u8 *buf) { u32 i; CanRxMsg RxMessage; if( CAN_MessagePending(CAN1,CAN_FIFO0)0)return 0; //没有接收到数据,直接退出 CAN_Receive(CAN1, CAN_FIFO0, RxMessage);//读取数据 for(i0;i8;i) buf[i]RxMessage.Data[i]; return RxMessage.DLC; } //电机参数定义以G9型号为例可根据实际电机修改 #define P_MIN (-12.5f) #define P_MAX (12.5f) #define V_MIN (-45.0f) #define V_MAX (45.0f) #define KP_MIN (0.0f) #define KP_MAX (500.0f) #define KD_MIN (0.0f) #define KD_MAX (5.0f) #define T_MIN (-54.0f) #define T_MAX (54.0f) /** *brief将浮点数转换为指定位宽的无符号定点整数 *paramx输入浮点值 *paramx_min量程下限 *paramx_max量程上限 *parambits目标位宽(1~16) *return定点无符号整数值(0~2^bits-1) */ int float_to_uint(float x, float x_min, float x_max, int bits) { float span x_max - x_min; float offset x_min; return(int)((x - offset)*((float)((1 bits) - 1)) / span); } /** *brief将无符号定点整数转换为浮点数 *paramx_int输入定点值 *paramx_min量程下限 *paramx_max量程上限 *parambits原始位宽 *return浮点值 */ float uint_to_float(int x_int, float x_min, float x_max, int bits) { float span x_max - x_min; float offset x_min; return ((float)x_int) * span / ((float)((1 bits) - 1)) offset; } /** * brief 将参数打包为CAN控制帧 * * 协议格式大端序8字节 *param *msg 控制帧数组 *param p_des输入期望位置值 *param v_des 输入期望速度值 *param Kp 输入Kp值 *param Kd 输入Kd值 *param t_ff 输入前馈扭矩值 */ void pack_command_frame(uint8_t *data, float p_des, float v_des, float Kp, float Kd, float tff) { /* 浮点值转换为对应位宽的无符号整数 */ int32_t pos_int float_to_uint(p_des, P_MIN, P_MAX, 16); int32_t vel_int float_to_uint(v_des, V_MIN, V_MAX, 12); int32_t kp_int float_to_uint(Kp, KP_MIN, KP_MAX, 12); int32_t kd_int float_to_uint(Kd, KD_MIN, KD_MAX, 12); int32_t t_int float_to_uint(tff, T_MIN, T_MAX, 12); /* 按协议布局逐字节填充 */ data[0] (uint8_t)(pos_int 8); data[1] (uint8_t)(pos_int 0xFF); data[2] (uint8_t)(vel_int 4); data[3] (uint8_t)(((vel_int 0x0F) 4) | ((kp_int 8) 0x0F)); data[4] (uint8_t)(kp_int 0xFF); data[5] (uint8_t)(kd_int 4); data[6] (uint8_t)(((kd_int 0x0F) 4) | ((t_int 8) 0x0F)); data[7] (uint8_t)(t_int 0xFF); } /** * brief 解析 CAN 控制命令帧提取控制参数 * * 协议格式 * * | 字节 | 位宽 | 内容 | 物理量程 | 说明 | * |-------|------|-------------- |----------------------- |------------------------ | * | [0..1] | 16 | 目标位置 | P_MIN ~ P_MAX [rad] | 高位在前 | * | [2..3] | 12 | 目标速度 | V_MIN ~ V_MAX [rad/s] | 字节 2 高 8 位字节 3 高 4 位 | * | [3..4] | 12 | 比例增益 kp | 0 ~ KP_MAX [N·m/rad] | 字节 3 低 4 位字节 4 | * | [5..6] | 12 | 微分增益 kd | 0 ~ KD_MAX [N·m·s/rad] | 字节 5 高 8 位字节 6 高 4 位 | * | [6..7] | 12 | 前馈扭矩 | 动态计算 ±T_MAX [N·m] | 字节 6 低 4 位字节 7 | * * 解码使用与 pack_command_frame 对称的映射关系和字节序。 */ void unpack_command_frame(uint8_t* data, float *commands) { /* 1. 从字节流重组无符号整数 */ uint16_t pos_raw ((uint16_t)data[0] 8) | data[1]; uint16_t vel_raw ((uint16_t)data[2] 4) | (data[3] 4); uint16_t kp_raw ((uint16_t)(data[3] 0x0F) 8) | data[4]; uint16_t kd_raw ((uint16_t)data[5] 4) | (data[6] 4); uint16_t tq_raw ((uint16_t)(data[6] 0x0F) 8) | data[7]; commands[0] uint_to_float(pos_raw, P_MIN, P_MAX, 16); commands[1] uint_to_float(vel_raw, V_MIN, V_MAX, 12); commands[2] uint_to_float(kp_raw, 0.0f, KP_MAX, 12); commands[3] uint_to_float(kd_raw, 0.0f, KD_MAX, 12); commands[4] uint_to_float(tq_raw, T_MIN, T_MAX, 12); } /** * brief 发送模式切换帧 * param motor_id 目标电机ID * param cmd_code 命令码0xFC使能运行0xFD待机0xFE置零0xFB标定 * return 0成功 */ u8 Can_Send_ModeFrame(uint8_t motor_id,uint8_t cmd_code) { uint8_t buf[8]; //不能直接 uint8_t buf[8]{0xFF,... ,cmd_code}; 初始化列表不能带变量 buf[0] 0xFF; buf[1] 0xFF; buf[2] 0xFF; buf[3] 0xFF; buf[4] 0xFF; buf[5] 0xFF; buf[6] 0xFF; buf[7] cmd_code; return Can_Send_Msg_Id(motor_id,buf,8); } u8 Can_Send_Msg_Id(uint16_t stdid,u8* msg,u8 len) { u8 mbox; u16 i0; CanTxMsg TxMessage; TxMessage.StdIdstdid; TxMessage.ExtId0x00; TxMessage.IDECAN_Id_Standard; TxMessage.RTRCAN_RTR_Data; TxMessage.DLClen; for(i0;ilen;i) TxMessage.Data[i]msg[i]; mbox CAN_Transmit(CAN1, TxMessage); i0; while((CAN_TransmitStatus(CAN1, mbox)CAN_TxStatus_Failed)(i0XFFF))i; if(i0XFFF)return 1; return 0; }
返回列表