반응형

https://youtube.com/live/AaawBcSBXX0

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

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

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

4채널릴레이는 어느정도 했고 이번에는 온습도센서를 처리해보도록 하겠습니다!

1.녹칸다가 23편에서 만든 예제2번을 그대로 적용한다음, modbus 4채널릴레이의 매뉴얼에 보면 릴레이의 on/off상태를 읽어오는 명령이 있는데, 이 명령을 이용해서 슬레이브쪽 릴레이의 작동상태를 마스터에서 알수있도록 하시오!(usart2출력)

 

/* 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){
  HAL_UART_Transmit(&huart1, nockanda_req[btn_num], sizeof(nockanda_req[btn_num]), 100);
  if(HAL_UART_Receive(&huart1, res, 8, 100) == HAL_OK){
  }
  HAL_Delay(200);
}
/* USER CODE END 0 */

/* USER CODE BEGIN 2 */
 uint32_t nockanda_t = 0;
 /* USER CODE END 2 */
 /* Infinite loop */
 /* USER CODE BEGIN WHILE */
 while (1)
 {
	  //100밀리초 간격으로 4채널릴레이에게 릴레이 상태를 물어본다!
	  if(HAL_GetTick() - nockanda_t >= 100){
		  nockanda_t = HAL_GetTick();
		  uint8_t req[] = {0x01,0x01,0x00,0x00,0x00,0x08,0x3D,0xCC};
		  HAL_UART_Transmit(&huart1, req, sizeof(req), 100);
		  //릴레이로부터 응답을 수신함!
		  //HAL_Delay(100);
		  if(HAL_UART_Receive(&huart1, res, 6, 100) == HAL_OK){
			//res[3]에 coil의 상태가 들어있다!
			uint8_t coils[4];
			for(int i = 0;i<4;i++){
				coils[i] = (res[3] >> i) & 0b00000001;
				sprintf(tx_buff,"COIL%d = %s,",i,coils[i] ? "ON" : "OFF");
				HAL_UART_Transmit(&huart2, tx_buff, strlen(tx_buff), 100);
			}
		   HAL_UART_Transmit(&huart2, "\n", 1, 100);
		  }
	  }
	  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 */
 }


2.예제1번에서 녹칸다가 버튼을 무지하게 빠르게 누르게되면 read coils쪽 코드가 HAL_Delay에 의해서 멈추게 된다! 이 부분을 freeRTOS를 이용해서 간단하게 극복해보시오!
task1:녹칸다가 8개의 버튼중에 어떤 버튼을 눌렀는지를 대기열에 넣음!
task2:100밀리초 간격으로 read coils명령을 대기열에 넣음!
task3:대기열에 있는 내용을 수행해서 반영함

/* 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){
  HAL_UART_Transmit(&huart1, nockanda_req[btn_num], sizeof(nockanda_req[btn_num]), 100);
  if(HAL_UART_Receive(&huart1, res, 8, 100) == HAL_OK){
  }
}
typedef struct {
   uint8_t fc; //fc가 0x05면 write single coil, 0x01이면 read coils
   uint8_t btn_num;
} Msg_t;
//메시지 큐(전역)
osMessageQueueId_t dataQueue;
/* USER CODE END 0 */
/* USER CODE BEGIN 2 */
 //메시지큐(메인)
 dataQueue = osMessageQueueNew(
                   8,              // queue length
                   sizeof(Msg_t),  // item size
                   NULL);
 /* USER CODE END 2 */

void StartDefaultTask(void *argument)
{
 /* USER CODE BEGIN 5 */
	//8개의 버튼중에 어떤 버튼이 눌려졌는지를 대기열에 넣는다!
	Msg_t msg;
	msg.fc  = 0x05;
 /* Infinite loop */
 for(;;)
 {
	  if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1) == 0){
		  //큐에다가 버튼 0번이 눌려졌다고 넣어준다
		  msg.btn_num = 0;
		  osMessageQueuePut(dataQueue, &msg, 0, 0);
		  osDelay(200);
	  }
	  if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_8) == 0){
		  msg.btn_num = 2;
		  osMessageQueuePut(dataQueue, &msg, 0, 0);
		  osDelay(200);
	  }
	  if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_2) == 0){
		  msg.btn_num = 4;
		  osMessageQueuePut(dataQueue, &msg, 0, 0);
		  osDelay(200);
	  }
	  if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_6) == 0){
		  msg.btn_num = 6;
		  osMessageQueuePut(dataQueue, &msg, 0, 0);
		  osDelay(200);
	  }
	  if(HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_5) == 0) {
		  msg.btn_num = 1;
		  osMessageQueuePut(dataQueue, &msg, 0, 0);
		  osDelay(200);
	  }

	  if(HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_7) == 0){
		  msg.btn_num = 3;
		  osMessageQueuePut(dataQueue, &msg, 0, 0);
		  osDelay(200);
	  }
	  if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_11) == 0){
		  msg.btn_num = 5;
		  osMessageQueuePut(dataQueue, &msg, 0, 0);
		  osDelay(200);
	  }
	  if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_12) == 0){
		  msg.btn_num = 7;
		  osMessageQueuePut(dataQueue, &msg, 0, 0);
		  osDelay(200);
	  }
	  osDelay(1); //이녀석 필수!
 }
 /* USER CODE END 5 */
/* USER CODE END Header_StartTask02 */
void StartTask02(void *argument)
{
 /* USER CODE BEGIN StartTask02 */
	//100밀리초 간격으로 read coils에 대한 명령을 대기열에 넣는다!
	Msg_t msg;
	msg.fc = 0x01;
 /* Infinite loop */
 for(;;)
 {
	  osMessageQueuePut(dataQueue, &msg, 0, 0);
     osDelay(100);
 }

/* USER CODE END Header_StartTask03 */
void StartTask03(void *argument)
{
 /* USER CODE BEGIN StartTask03 */
	//대기열에 뭔가 기다리는게 있으면 순서대로 뺴서 처리한다!
	Msg_t msg;
 /* Infinite loop */
 for(;;)
 {
	  osMessageQueueGet(dataQueue, &msg, NULL, osWaitForever);
	  if(msg.fc == 0x01){
		  uint8_t req[] = {0x01,0x01,0x00,0x00,0x00,0x08,0x3D,0xCC};
		  HAL_UART_Transmit(&huart1, req, sizeof(req), 100);
		  //릴레이로부터 응답을 수신함!
		  //HAL_Delay(100);
		  if(HAL_UART_Receive(&huart1, res, 6, 100) == HAL_OK){
			//res[3]에 coil의 상태가 들어있다!
			uint8_t coils[4];
			for(int i = 0;i<4;i++){
				coils[i] = (res[3] >> i) & 0b00000001;
				sprintf(tx_buff,"COIL%d = %s,",i,coils[i] ? "ON" : "OFF");
				HAL_UART_Transmit(&huart2, tx_buff, strlen(tx_buff), 100);
			}
		   HAL_UART_Transmit(&huart2, "\n", 1, 100);
		  }
	  }else if(msg.fc == 0x05){
		  //task1으로부터 온 메시지
		  control_relay(msg.btn_num);
	  }
 }
 /* USER CODE END StartTask03 */
}


3.modbus rtu 온습도센서를 연결해서 온도를 측정해서 putty화면에 출력하시오!

/* USER CODE BEGIN 2 */
 uint8_t res[8];
 uint8_t tx_buff[100];
 /* USER CODE END 2 */


while (1)
 {
	  uint8_t req[] = {0x01,0x04,0x00,0x01,0x00,0x01,0x60,0x0A};
	  HAL_UART_Transmit(&huart1, req, sizeof(req), 100);
	  if(HAL_UART_Receive(&huart1, res, 7, 100) == HAL_OK){
	 		//USART2로 출력!
	 		HAL_UART_Transmit(&huart2, "res = ", 6, 100);
	 		for(int i = 0;i<7;i++){
	 		  sprintf(tx_buff,"%02X, ",res[i]);
	 		  HAL_UART_Transmit(&huart2, tx_buff, strlen(tx_buff), 100);
	 	  }
	 	  HAL_UART_Transmit(&huart2, "\n", 1, 100);
	 	  //온도계산 res[3] res[4]
	 	  int16_t temp = (res[3] << 8) | res[4];
	 	  sprintf(tx_buff,"temp = %.1f\n",temp/10.0);
	 	 HAL_UART_Transmit(&huart2, tx_buff, strlen(tx_buff), 100);
	   }
	  HAL_Delay(1000);
   /* USER CODE END WHILE */
   /* USER CODE BEGIN 3 */
 }


4.modbus rtu 온습도센서를 연결해서 습도를 측정해서 putty화면에 출력하시오!

/* USER CODE BEGIN 2 */
 uint8_t res[8];
 uint8_t tx_buff[100];
 /* USER CODE END 2 */


while (1)
 {
	  uint8_t req[] = {0x01,0x04,0x00,0x02,0x00,0x01,0x90,0x0A};
	  HAL_UART_Transmit(&huart1, req, sizeof(req), 100);
	  if(HAL_UART_Receive(&huart1, res, 7, 100) == HAL_OK){
	 		//USART2로 출력!
	 		HAL_UART_Transmit(&huart2, "res = ", 6, 100);
	 		for(int i = 0;i<7;i++){
	 		  sprintf(tx_buff,"%02X, ",res[i]);
	 		  HAL_UART_Transmit(&huart2, tx_buff, strlen(tx_buff), 100);
	 	  }
	 	  HAL_UART_Transmit(&huart2, "\n", 1, 100);
	 	  //습도계산 res[3] res[4]
	 	  uint16_t humi = (res[3] << 8) | res[4];
	 	  sprintf(tx_buff,"humi = %.1f\n",humi/10.0);
	 	 HAL_UART_Transmit(&huart2, tx_buff, strlen(tx_buff), 100);
	   }
	  HAL_Delay(1000);
   /* USER CODE END WHILE */
   /* USER CODE BEGIN 3 */
 }


5.온도와 습도를 동시에 측정해서 putty화면에 출력하시오!

/* USER CODE BEGIN 2 */
 uint8_t res[8];
 uint8_t tx_buff[100];
 /* USER CODE END 2 */

while (1)
 {
	  uint8_t req[] = {0x01,0x04,0x00,0x01,0x00,0x02,0x20,0x0B};
	  HAL_UART_Transmit(&huart1, req, sizeof(req), 100);
	  if(HAL_UART_Receive(&huart1, res, 9, 100) == HAL_OK){
	 		//USART2로 출력!
	 		HAL_UART_Transmit(&huart2, "res = ", 6, 100);
	 		for(int i = 0;i<9;i++){
	 		  sprintf(tx_buff,"%02X, ",res[i]);
	 		  HAL_UART_Transmit(&huart2, tx_buff, strlen(tx_buff), 100);
	 	  }
	 	  HAL_UART_Transmit(&huart2, "\n", 1, 100);
	 	  //온도 res[3] + res[4]
	 	  //습도 res[5] + res[6]
	 	  int16_t temp = (res[3] << 8) | res[4];
	 	  uint16_t humi = (res[5] << 8) | res[6];
	 	  sprintf(tx_buff,"temp = %.1f, humi = %.1f\n",temp/10.0,humi/10.0);
	 	 HAL_UART_Transmit(&huart2, tx_buff, strlen(tx_buff), 100);
	   }
	  HAL_Delay(1000);
   /* USER CODE END WHILE */
   /* USER CODE BEGIN 3 */
 }


6.측정한 온도와 습도를 1602LCD에 출력하시오! 

//BEGIN0에 i2c 1602LCD관련코드 링크타고가서 추가하기!

/* USER CODE BEGIN 2 */
 uint8_t res[9];
 uint8_t tx_buff[100];
 uint8_t line1[20];
 uint8_t line2[20];
 LCD_INIT(); //1회호출(메인루프 시작전)
 /* USER CODE END 2 */

while (1)
 {
	  uint8_t req[] = {0x01,0x04,0x00,0x01,0x00,0x02,0x20,0x0B};
	  HAL_UART_Transmit(&huart1, req, sizeof(req), 100);
	  if(HAL_UART_Receive(&huart1, res, 9, 100) == HAL_OK){
	 		//USART2로 출력!
	 		HAL_UART_Transmit(&huart2, "res = ", 6, 100);
	 		for(int i = 0;i<9;i++){
	 		  sprintf(tx_buff,"%02X, ",res[i]);
	 		  HAL_UART_Transmit(&huart2, tx_buff, strlen(tx_buff), 100);
	 	  }
	 	  HAL_UART_Transmit(&huart2, "\n", 1, 100);
	 	  //온도 res[3] + res[4]
	 	  //습도 res[5] + res[6]
	 	  int16_t temp = (res[3] << 8) | res[4];
	 	  uint16_t humi = (res[5] << 8) | res[6];
	 	  sprintf(tx_buff,"temp = %.1f, humi = %.1f\n",temp/10.0,humi/10.0);
	 	  HAL_UART_Transmit(&huart2, tx_buff, strlen(tx_buff), 100);
	 	  //1602LCD에 출력하기
	 	  LCD_CLEAR();
	 	  sprintf(line1,"TEMP = %.1f'C",temp/10.0);
	 	  sprintf(line2,"HUMI = %.1f%c",humi/10.0,'%');
	 	  LCD_XY(0, 0) ; LCD_PUTS(line1);
	 	  LCD_XY(0, 1) ; LCD_PUTS(line2);
	   }
	  HAL_Delay(1000);
 }
반응형
Posted by 덕력킹
,