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 */
}
posted @ 2019-12-23 20:10  DingJie1024  阅读(1648)  评论(0编辑  收藏  举报