반응형

https://youtube.com/live/oMZoDk0ourA

[STM32#23] RS485 to TTL모듈을 이용해서 modbus rtu로 4채널릴레이(relay)와 온습도센서(XY-MD02) 제어하는 방법!(녹칸다 내맘대로 STM32)

심심한녹칸다의 내맘대로 STM32시리즈이다!

STM32시리즈의 모든 자료는 구글 슬라이드에 작성하고 모두에게 공유되어있음!
https://docs.google.com/presentation/d/1myA5iYbjuKsLWLqtRLKAiRfwUwvqB1d1RGjiMIIgp3I/edit?slide=id.g3ab12818c94_4_1#slide=id.g3ab12818c94_4_1

산업용 통신인 modbus rtu를 해보도록 하겠습니다!

 

(연결)


1.STM32가 RS485릴레이의 채널0을 1초간격으로 on/off하도록 하시오!

/* USER CODE BEGIN 2 */
 uint8_t on_req[] = {0x01,0x05,0x00,0x00,0xFF,0x00,0x8C,0x3A};
 uint8_t off_req[] = {0x01,0x05,0x00,0x00,0x00,0x00,0xCD,0xCA};
 uint8_t res[8];
 uint8_t tx_buff[100];
 /* USER CODE END 2 */
 /* Infinite loop */
 /* USER CODE BEGIN WHILE */
 while (1)
 {
	  //채널0 ON명령어 전송!(01 05 00 00 FF 00 8C 3A)
	  HAL_UART_Transmit(&huart1, on_req, sizeof(on_req), 100);
	  HAL_UART_Transmit(&huart2, "on_req sent!\n", 13, 100);
	  //릴레이로부터 응답을 수신함!
	  //HAL_Delay(100);
	  if(HAL_UART_Receive(&huart1, res, 8, 100) == HAL_OK){
		  //USART2로 출력!
		  HAL_UART_Transmit(&huart2, "res = ", 6, 100);
		  for(int i = 0;i<8;i++){
			  sprintf(tx_buff,"%02X, ",res[i]);
			  HAL_UART_Transmit(&huart2, tx_buff, strlen(tx_buff), 100);
		  }
		  HAL_UART_Transmit(&huart2, "\n", 1, 100);
	  }
	  HAL_Delay(1000);

	  //채널0 OFF명령어 전송!(01 05 00 00 00 00 CD CA)
	  HAL_UART_Transmit(&huart1, off_req, sizeof(off_req), 100);
	  HAL_UART_Transmit(&huart2, "off_req sent!\n", 14, 100);
	  //HAL_Delay(100);
	  //릴레이로부터 응답을 수신함!
	  if(HAL_UART_Receive(&huart1, res, 8, 100) == HAL_OK){
		  //USART2로 출력!
		  HAL_UART_Transmit(&huart2, "res = ", 6, 100);
		  for(int i = 0;i<8;i++){
			  sprintf(tx_buff,"%02X, ",res[i]);
			  HAL_UART_Transmit(&huart2, tx_buff, strlen(tx_buff), 100);
		  }
		  HAL_UART_Transmit(&huart2, "\n", 1, 100);
	  }
	  HAL_Delay(1000);
   /* USER CODE END WHILE */
   /* USER CODE BEGIN 3 */
 }


2.녹칸다의 STM32쉴드에 붙어있는 버튼 8개를 이용해서 4채널 릴레이를 모두 on/off할수있는 기능을 구현하시오!

/* USER CODE BEGIN 0 */
uint8_t nockanda_req[][8] = {
		{0x01,0x05,0x00,0x00,0xFF,0x00,0x8C,0x3A},
		{0x01,0x05,0x00,0x00,0x00,0x00,0xCD,0xCA},
		{0x01,0x05,0x00,0x01,0xFF,0x00,0xDD,0xFA},
		{0x01,0x05,0x00,0x01,0x00,0x00,0x9C,0x0A},
		{0x01,0x05,0x00,0x02,0xFF,0x00,0x2D,0xFA},
		{0x01,0x05,0x00,0x02,0x00,0x00,0x6C,0x0A},
		{0x01,0x05,0x00,0x03,0xFF,0x00,0x7C,0x3A},
		{0x01,0x05,0x00,0x03,0x00,0x00,0x3D,0xCA}
};
uint8_t res[8];
uint8_t tx_buff[100];
//btn_num은 0부터 7까지 눌려진 버튼의 번호이다!
void control_relay(int btn_num){
	//채널0 ON명령어 전송!(01 05 00 00 FF 00 8C 3A)
   HAL_UART_Transmit(&huart1, nockanda_req[btn_num], sizeof(nockanda_req[btn_num]), 100);
   HAL_UART_Transmit(&huart2, "on_req sent!\n", 13, 100);
   //릴레이로부터 응답을 수신함!
   //HAL_Delay(100);
   if(HAL_UART_Receive(&huart1, res, 8, 100) == HAL_OK){
	    //USART2로 출력!
	    HAL_UART_Transmit(&huart2, "res = ", 6, 100);
	    for(int i = 0;i<8;i++){
	  	  sprintf(tx_buff,"%02X, ",res[i]);
		  HAL_UART_Transmit(&huart2, tx_buff, strlen(tx_buff), 100);
	  }
	  HAL_UART_Transmit(&huart2, "\n", 1, 100);
   }
   HAL_Delay(200);
}
/* USER CODE END 0 */

while (1)
 {
	  if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1) == 0) control_relay(0);
	  if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_8) == 0) control_relay(2);
	  if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_2) == 0) control_relay(4);
	  if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_6) == 0) control_relay(6);
	  if(HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_5) == 0) control_relay(1);
	  if(HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_7) == 0) control_relay(3);
	  if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_11) == 0) control_relay(5);
	  if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_12) == 0) control_relay(7);
   /* USER CODE END WHILE */
   /* USER CODE BEGIN 3 */
 }


3.예제2에서 릴레이를 제어하는 8개의 커맨드가 있는데, 각 커맨드의 CRC16을 계산하는 함수를 이용해서 CRC16만 계산해서 출력하시오!

/* USER CODE BEGIN 0 */
uint8_t nockanda_req[][8] = {
		{0x01,0x05,0x00,0x00,0xFF,0x00,0x8C,0x3A}, //0
		{0x01,0x05,0x00,0x00,0x00,0x00,0xCD,0xCA}, //1
		{0x01,0x05,0x00,0x01,0xFF,0x00,0xDD,0xFA}, //2
		{0x01,0x05,0x00,0x01,0x00,0x00,0x9C,0x0A}, //3
		{0x01,0x05,0x00,0x02,0xFF,0x00,0x2D,0xFA}, //4
		{0x01,0x05,0x00,0x02,0x00,0x00,0x6C,0x0A}, //5
		{0x01,0x05,0x00,0x03,0xFF,0x00,0x7C,0x3A}, //6
		{0x01,0x05,0x00,0x03,0x00,0x00,0x3D,0xCA} //7
};
uint8_t res[8];
uint8_t tx_buff[100];
//함수의 프로토타입 선언
void control_relay(int btn_num);
uint16_t cal_crc(uint8_t *data, uint8_t len);
//btn_num은 0부터 7까지 눌려진 버튼의 번호이다!
void control_relay(int btn_num){
	uint16_t crc16 = cal_crc(nockanda_req[btn_num],6);
	sprintf(tx_buff,"btn_num= %d, crc16= %04x\n",btn_num,crc16);
	HAL_UART_Transmit(&huart2, tx_buff, strlen(tx_buff), 100);
   HAL_Delay(200);
}


uint16_t cal_crc(uint8_t *data, uint8_t len)
{
   uint16_t crc = 0xFFFF;
   for(uint8_t i = 0; i < len; i++)
   {
       crc ^= data[i];   // LSB부터 XOR
       for(uint8_t j = 0; j < 8; j++)
       {
           if(crc & 0x0001)
           {
               crc >>= 1;
               crc ^= 0xA001;   // Modbus polynomial
           }
           else
           {
               crc >>= 1;
           }
       }
   }
   return crc;
}
while (1)
 {
	  if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1) == 0) control_relay(0);
	  if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_8) == 0) control_relay(2);
	  if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_2) == 0) control_relay(4);
	  if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_6) == 0) control_relay(6);
	  if(HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_5) == 0) control_relay(1);
	  if(HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_7) == 0) control_relay(3);
	  if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_11) == 0) control_relay(5);
	  if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_12) == 0) control_relay(7);
   /* USER CODE END WHILE */
   /* USER CODE BEGIN 3 */
 }


4.modbus rtu명령어에서 CRC16자리를 비워두고 직접 계산해서 대입한다음 명령을 전송하시오!

/* USER CODE BEGIN 0 */
uint8_t nockanda_req[][8] = {
		{0x01,0x05,0x00,0x00,0xFF,0x00,0x00,0x00}, //0
		{0x01,0x05,0x00,0x00,0x00,0x00,0x00,0x00}, //1
		{0x01,0x05,0x00,0x01,0xFF,0x00,0x00,0x00}, //2
		{0x01,0x05,0x00,0x01,0x00,0x00,0x00,0x00}, //3
		{0x01,0x05,0x00,0x02,0xFF,0x00,0x00,0x00}, //4
		{0x01,0x05,0x00,0x02,0x00,0x00,0x00,0x00}, //5
		{0x01,0x05,0x00,0x03,0xFF,0x00,0x00,0x00}, //6
		{0x01,0x05,0x00,0x03,0x00,0x00,0x00,0x00} //7
};
uint8_t res[8];
uint8_t tx_buff[100];
//함수의 프로토타입 선언
void control_relay(int btn_num);
uint16_t cal_crc(uint8_t *data, uint8_t len);
//btn_num은 0부터 7까지 눌려진 버튼의 번호이다!
void control_relay(int btn_num){
	uint16_t crc16 = cal_crc(nockanda_req[btn_num],6);
	nockanda_req[btn_num][6] = crc16 & 0x00FF; //CRC_L
	nockanda_req[btn_num][7] = crc16 >> 8; //CRC_H
	HAL_UART_Transmit(&huart1, nockanda_req[btn_num], sizeof(nockanda_req[btn_num]), 100);
  HAL_UART_Transmit(&huart2, "on_req sent!\n", 13, 100);
  //릴레이로부터 응답을 수신함!
  //HAL_Delay(100);
  if(HAL_UART_Receive(&huart1, res, 8, 100) == HAL_OK){
		//USART2로 출력!
		HAL_UART_Transmit(&huart2, "res = ", 6, 100);
		for(int i = 0;i<8;i++){
		  sprintf(tx_buff,"%02X, ",res[i]);
		  HAL_UART_Transmit(&huart2, tx_buff, strlen(tx_buff), 100);
	  }
	  HAL_UART_Transmit(&huart2, "\n", 1, 100);
  }
   HAL_Delay(200);
}

uint16_t cal_crc(uint8_t *data, uint8_t len)
{
   uint16_t crc = 0xFFFF;
   for(uint8_t i = 0; i < len; i++)
   {
       crc ^= data[i];   // LSB부터 XOR
       for(uint8_t j = 0; j < 8; j++)
       {
           if(crc & 0x0001)
           {
               crc >>= 1;
               crc ^= 0xA001;   // Modbus polynomial
           }
           else
           {
               crc >>= 1;
           }
       }
   }
   return crc;
}
while (1)
 {
	  if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1) == 0) control_relay(0);
	  if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_8) == 0) control_relay(2);
	  if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_2) == 0) control_relay(4);
	  if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_6) == 0) control_relay(6);
	  if(HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_5) == 0) control_relay(1);
	  if(HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_7) == 0) control_relay(3);
	  if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_11) == 0) control_relay(5);
	  if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_12) == 0) control_relay(7);
   /* USER CODE END WHILE */
   /* USER CODE BEGIN 3 */
 }
반응형
Posted by 덕력킹
,