CAN总线_生产线环境监测
一、设备准备
- PC一台‘
- 网关一个
- CAN节点三个
- 温湿度传感器两个
- 火焰传感器一个
- USB接口CAN调试器
二、系统拓扑图
三、知识链接
四、完善工程
4.1在 user_can.c 的 void CAN_User_Config(CAN_HandleTypeDef* hcan )函数中添加如下代码
void CAN_User_Config(CAN_HandleTypeDef* hcan ) { CAN_FilterTypeDef sFilterConfig; HAL_StatusTypeDef HAL_Status; sFilterConfig.FilterBank = 0; //过滤器 0 sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;//屏蔽位模式 sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; //32 位宽 sFilterConfig.FilterIdHigh = 0x0000; //32 位 ID sFilterConfig.FilterIdLow = 0x0000; sFilterConfig.FilterMaskIdHigh = 0x0000; //32 位 MASK sFilterConfig.FilterMaskIdLow = 0x0000; sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0; //接收到的报文放入到 FIFO0 中 sFilterConfig.FilterActivation = ENABLE; //激活过滤器 sFilterConfig.SlaveStartFilterBank = 0; HAL_Status=HAL_CAN_ConfigFilter(hcan, &sFilterConfig); HAL_Status=HAL_CAN_Start(hcan); //开启 CAN if(HAL_Status!=HAL_OK) { printf("开启 CAN 失败\r\n"); } HAL_Status=HAL_CAN_ActivateNotification(hcan, CAN_IT_RX_FIFO0_MSG_PENDING); if(HAL_Status!=HAL_OK) { printf("开启挂起中段允许失败\r\n"); } }
4.2在 user_can.c 的 void can_start(void)函数中添加如下代码
/****************************************************************************** * FunctionName : void can_start(void) * Description : 启动CAN总线 * Parameters : none * Returns : none *******************************************************************************/ void can_start(void) { HAL_CAN_Start(&hcan); }
4.3在 user_can.c 的 void can_stop (void)函数中添加如代码
/****************************************************************************** * FunctionName : void can_stop(void) * Description : 停止CAN总线 * Parameters : none * Returns : none *******************************************************************************/ void can_stop(void) { HAL_CAN_Stop(&hcan); }
4.4在 user_can.c 的 uint8_t Can_Send_Msg(uint8_t* msg,uint8_t len)函数中添加 如下代码
/****************************************************************************** * FunctionName : uint8_t Can_Send_Msg(uint8_t* msg,uint8_t len) * Description : can发送一组数据(固定格式:ID为0X12,标准帧,数据帧) * Parameters : len:数据长度(最大为8) * msg:数据指针,最大为8个字节. * Returns : 0,成功; * 其他,失败; *******************************************************************************/ uint8_t Can_Send_Msg(uint8_t* msg,uint8_t len) { uint16_t i=0; uint8_t data[8]; CAN_TxHeaderTypeDef TxMeg; TxMeg.StdId=0x12; // 标准标识符 TxMeg.ExtId=0x12; // 设置扩展标示符 TxMeg.IDE=CAN_ID_STD; // 标准帧 TxMeg.RTR= CAN_RTR_DATA; // 数据帧 TxMeg.DLC=len; // 要发送的数据长度 for(i=0;i<len;i++) { data[i]=msg[i]; } if (HAL_CAN_AddTxMessage(&hcan, &TxMeg, data, &TxMailbox) != HAL_OK) { printf("Can send data error\r\n"); } else { printf("Can send data success\r\n"); } return 0; }
4.5在 user_can.c 的 uint8_t Can_Send_Msg_StdId(uint16_t My_StdId,uint8_t len,uint8_t Type_Sensor)函数中添加如下代码
/****************************************************************************** * FunctionName : uint8_t Can_Send_Msg_StdId(uint16_t My_StdId,uint8_t len,uint8_t Type_Sensor) * Description : can发送一组数据(固定格式:ID为My_StdId,标准帧,数据帧) * Parameters : My_StdId:标准标识符 * len:数据长度(最大为8) * msg:数据指针,最大为8个字节. * Returns : 0,成功; * 其他,失败; *******************************************************************************/ uint8_t Can_Send_Msg_StdId(uint16_t My_StdId,uint8_t len,uint8_t Type_Sensor) { CAN_TxHeaderTypeDef TxMeg; ValueType ValueType_t; uint8_t vol_H,vol_L; uint16_t i=0; uint8_t data[8]; TxMeg.StdId=My_StdId; // 标准标识符 TxMeg.ExtId=0x00; // 设置扩展标示符 TxMeg.IDE=CAN_ID_STD; // 标准帧 TxMeg.RTR=CAN_RTR_DATA; // 数据帧 TxMeg.DLC=len; // 要发送的数据长度 for(i=0;i<len;i++) { data[i]=0; } data[0] = Sensor_Type_t; data[4] = (uint8_t)My_StdId; printf("Can_Send_Msg_StdId >>My_StdId 标准帧 ID= %x \r\n",My_StdId); printf("Can_Send_Msg_StdId >>Sensor_Type_t %d \r\n",data[0]); ValueType_t=ValueTypes(Type_Sensor); printf("Can_Send_Msg_StdId >>ValueType_t %d \r\n",ValueType_t); switch(ValueType_t) { case Value_ADC: vol_H = (vol&0xff00)>>8; vol_L = vol&0x00ff; data[1]=vol_H; data[2]=vol_L; printf("Can_Send_Msg_StdId >> Value_ADC TxMessage.Data[1]=vol_L %d \r\n",data[1]); printf("Can_Send_Msg_StdId >> Value_ADC TxMessage.Data[2]=vol_L %d \r\n",data[2]); break; case Value_Switch: data[1]=switching; data[2]=0; break; case Value_I2C: data[1]=sensor_tem; data[2]=sensor_hum; printf("Can_Send_Msg_StdId >> Value_I2C TxMessage.Data[1]=vol_L %d \r\n",data[1]); printf("Can_Send_Msg_StdId >> Value_I2C TxMessage.Data[2]=vol_L %d \r\n",data[2]); break; default: break; } if (HAL_CAN_AddTxMessage(&hcan, &TxMeg, data, &TxMailbox) != HAL_OK) { printf("Can send data error\r\n"); } else { printf("Can send data success\r\n"); } return 0; }
4.6在 user_can.c 的 HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)函数中添加如下代码
//CAN中断回调函数 void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan) { CAN_RxHeaderTypeDef RxMeg; uint8_t Data[8] = {0}; HAL_StatusTypeDef HAL_RetVal; int i; RxMeg.StdId=0x00; RxMeg.ExtId=0x00; RxMeg.IDE=0; RxMeg.DLC=0; HAL_RetVal=HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &RxMeg, Data); if ( HAL_OK==HAL_RetVal) { for(i=0;i<RxMeg.DLC;i++) { Can_data[i]= Data[i]; printf("%02X ",Data[i]); } printf("\r\n"); flag_send_data=1; } }
4.7将该工程配置为网关节点工程,在 main.c 的 int main(void)函数中添加如下代码
对工程进行编译,并对生成的hex文件剪切到另一个文件夹(随意新建),并重命名为"网关节点,hex"
int main(void) { /* USER CODE BEGIN 1 */ ValueType Value_Type; /* 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_CAN_Init(); MX_ADC1_Init(); MX_USART1_UART_Init(); MX_USART2_UART_Init(); MX_TIM2_Init(); /* USER CODE BEGIN 2 */ SHT1x_init(); //温湿度传感器初始化 InfraredSensor_Init(); CAN_User_Config(&hcan); //CAN总线配置 Can_STD_ID=STMFLASH_ReadHalfWord(FLASE_M3_ADDR); //配置CAN节点发送的标准帧ID Sensor_Type_t=STMFLASH_ReadHalfWord(FLASH_Sensor_Type); //配置M3主控模块采集的传感器类型 open_usart1_receive_interrupt(); //启动USART1串口中断 can_start(); //启动CAN总线 /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ if(1) { Value_Type=ValueTypes(Sensor_Type_t); switch(Value_Type) { case Value_ADC: //光照 空气 火焰 可燃气体 sensor_number=1; vol=Get_Voltage(); printf("vol=Get_Voltage ===== %x \r\n",vol); break; case Value_Switch: //人体 红外 声音 sensor_number=1; switching=Switching_Value(); printf("switching=Switching_Value== %d \r\n",switching); break; case Value_I2C: sensor_number=2; SHT1x_get_temperature(&sensor_tem); //温度 SHT1x_get_relative_humidity(&sensor_hum); //湿度 printf("sensor_tem ===== %d :;sensor_hum===%d \r\n",(int)sensor_tem,(int)sensor_hum); break; default: break; } //CAN 节点发送传感器数据至 CAN 总线 Master_To_Gateway((uint8_t)Can_STD_ID, Value_Type, vol, switching, sensor_hum, sensor_tem ); } HAL_Delay(1500); //USART1 通过M3主控模块配置工具配置采集传感器类型 或 或者CAN发送标准帧ID (注标准帧不能超过0 to 0x7FF) if(flag_send_data==1) { CAN_Master_To_Gateway( Can_data,3); flag_send_data=0; } /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ }
4.8将该工程配置为终端节点工程,在 main.c 的 int main(void)函数中将上一步添加的代 码删除,添加新的代码,如粗体部分下
对工程进行编译,并对生成的hex文件,并重命名为“终端节点.hex”
int main(void) { …… while (1) { /* USER CODE END WHILE */ if(1) { Value_Type=ValueTypes(Sensor_Type_t); switch(Value_Type) { …… } //CAN 节点发送传感器数据至 CAN 总线 Can_Send_Msg_StdId(Can_STD_ID,8,Sensor_Type_t); } HAL_Delay(1500); …… /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ }