반응형

https://youtube.com/live/xWxbcANp3ac

[STM32#25] stm32를 modbus rtu 슬레이브(slave)로 C# winform을 마스터(master)로 설정해서 제어하는 방법(1)!(녹칸다 내맘대로 STM32)

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

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

이제 stm32가 마스터가 아니라 슬레이브가 되는 것입니다~~!

1.C#윈폼에서 버튼을 2개 생성하고 ON버튼을 누르면 STM32의 PB3의 LED가 켜지고, OFF버튼을 누르면 꺼지도록 하시오!

/* USER CODE BEGIN 0 */
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;
}
/* USER CODE END 0 */
/* USER CODE BEGIN 2 */
 //녹칸다의 STM32쉴드의 8개의 LED를 배열로 뭉쳐놓은것!
 GPIO_TypeDef *mygroup[] = {GPIOB,GPIOB,GPIOB,GPIOB,GPIOB,GPIOB,GPIOC,GPIOB};
 uint16_t mypin[] = {GPIO_PIN_3,GPIO_PIN_13,GPIO_PIN_5,GPIO_PIN_14,GPIO_PIN_4,GPIO_PIN_15,GPIO_PIN_4,GPIO_PIN_7};
 uint8_t slave_id = 0x01;
 uint8_t tx_buff[100];
 uint8_t req[8];
 /* USER CODE END 2 */

while (1)
 {
	  //usart1은 RS485통신, usart2는 PC와 통신
	  //usart1으로 수신해서 usart2로 결과를 송신한다!
	  if(HAL_UART_Receive(&huart1, req, 8, 100) == HAL_OK){
		  //응답예시데이터
		  uint8_t id = req[0];
		  //내 id에게 req가 왔을때만 res를 전송한다!
		  if(id == slave_id){
			  uint8_t fc = req[1];
			  uint16_t coil_addr = (req[2] << 8) | req[3];
			  uint16_t coil_data = (req[4] << 8) | req[5];
			  uint16_t crc16 = (req[7] << 8) | req[6];
			  //STM32가 CRC16을 계산함!
			  uint16_t my_crc16 = cal_crc(req,6);
			  if(crc16 == my_crc16){
				  sprintf(tx_buff,"id=%02X, fc=%02X, addr=%04X, data=%04X, crc=%04X\n",id,fc,coil_addr,coil_data,crc16);
				  HAL_UART_Transmit(&huart2, tx_buff, strlen(tx_buff), 100);
				  //write single coil명령어 수행
				  if(coil_data == 0xFF00){
					  //ON
					  HAL_GPIO_WritePin(mygroup[coil_addr], mypin[coil_addr], 1);
				  }else{
					  //OFF
					  HAL_GPIO_WritePin(mygroup[coil_addr], mypin[coil_addr], 0);
				  }
				  //응답전송! 그런데 FC=0x05는 req와 res가 같다!
				  HAL_UART_Transmit(&huart1, req, 8, 100);
			  }else{
				  HAL_UART_Transmit(&huart2, "CRC16 ERROR!\n", 13, 100);
			  }
		  }
	  }
 }
private void button1_Click(object sender, EventArgs e)
        {
            //접속버튼 클릭
            serialPort1.BaudRate = 9600;
            serialPort1.PortName = textBox1.Text;

            serialPort1.Open();

            if (serialPort1.IsOpen)
            {
                MessageBox.Show("연결완료!");
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            if (serialPort1.IsOpen)
            {
                byte[] req = { 0x01, 0x05, 0x00, 0x00, 0xFF, 0x00, 0x8C, 0x3A };
                serialPort1.Write(req, 0, 8);
            }
        }

        private void button3_Click(object sender, EventArgs e)
        {
            if (serialPort1.IsOpen)
            {
                byte[] req = { 0x01, 0x05, 0x00, 0x00, 0x00, 0x00, 0xCD, 0xCA };
                serialPort1.Write(req, 0, 8);
            }
        }

private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            //슬레이브로부터 8개의 데이터가 응답으로 올 예정이다!
            byte[] res = new byte[8];
            int pos = 0;
            for (int i = 0; i < 8; i++)
            {
                res[pos++] = (byte)serialPort1.ReadByte();
            }
            
            richTextBox1.Text += "[응답] ";
            for(int i = 0; i < 8; i++)
            {
                richTextBox1.Text += res[i].ToString("X") + ", ";
            }
            richTextBox1.Text += "\n";
        }


2.예제1번에서 PB3번 LED만 제어했던것을 녹칸다의 STM32쉴드에 붙어있는 8개의 LED를 제어할 수 있는 기능으로 확장하시오!

/* USER CODE BEGIN 0 */
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;
}
/* USER CODE END 0 */
/* USER CODE BEGIN 2 */
 //녹칸다의 STM32쉴드의 8개의 LED를 배열로 뭉쳐놓은것!
 GPIO_TypeDef *mygroup[] = {GPIOB,GPIOB,GPIOB,GPIOB,GPIOB,GPIOB,GPIOC,GPIOB};
 uint16_t mypin[] = {GPIO_PIN_3,GPIO_PIN_13,GPIO_PIN_5,GPIO_PIN_14,GPIO_PIN_4,GPIO_PIN_15,GPIO_PIN_4,GPIO_PIN_7};
 uint8_t slave_id = 0x01;
 uint8_t tx_buff[100];
 uint8_t req[8];
 /* USER CODE END 2 */

while (1)
 {
	  //usart1은 RS485통신, usart2는 PC와 통신
	  //usart1으로 수신해서 usart2로 결과를 송신한다!
	  if(HAL_UART_Receive(&huart1, req, 8, 100) == HAL_OK){
		  //응답예시데이터
		  uint8_t id = req[0];
		  //내 id에게 req가 왔을때만 res를 전송한다!
		  if(id == slave_id){
			  uint8_t fc = req[1];
			  uint16_t coil_addr = (req[2] << 8) | req[3];
			  uint16_t coil_data = (req[4] << 8) | req[5];
			  uint16_t crc16 = (req[7] << 8) | req[6];
			  //STM32가 CRC16을 계산함!
			  uint16_t my_crc16 = cal_crc(req,6);
			  if(crc16 == my_crc16){
				  sprintf(tx_buff,"id=%02X, fc=%02X, addr=%04X, data=%04X, crc=%04X\n",id,fc,coil_addr,coil_data,crc16);
				  HAL_UART_Transmit(&huart2, tx_buff, strlen(tx_buff), 100);
				  //write single coil명령어 수행
				  if(coil_data == 0xFF00){
					  //ON
					  HAL_GPIO_WritePin(mygroup[coil_addr], mypin[coil_addr], 1);
				  }else{
					  //OFF
					  HAL_GPIO_WritePin(mygroup[coil_addr], mypin[coil_addr], 0);
				  }
				  //응답전송! 그런데 FC=0x05는 req와 res가 같다!
				  HAL_UART_Transmit(&huart1, req, 8, 100);
			  }else{
				  HAL_UART_Transmit(&huart2, "CRC16 ERROR!\n", 13, 100);
			  }
		  }
	  }
 }
private void button1_Click(object sender, EventArgs e)
        {
            //접속버튼 클릭
            serialPort1.BaudRate = 9600;
            serialPort1.PortName = textBox1.Text;

            serialPort1.Open();

            if (serialPort1.IsOpen)
            {
                MessageBox.Show("연결완료!");
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            if (serialPort1.IsOpen) write_single_coil(0, true);
        }

        private void button3_Click(object sender, EventArgs e)
        {
            if (serialPort1.IsOpen) write_single_coil(0, false);
        }

        private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            //슬레이브로부터 8개의 데이터가 응답으로 올 예정이다!
            byte[] res = new byte[8];
            int pos = 0;
            for (int i = 0; i < 8; i++)
            {
                res[pos++] = (byte)serialPort1.ReadByte();
            }
            

            richTextBox1.Text += "[응답] ";
            for(int i = 0; i < 8; i++)
            {
                richTextBox1.Text += res[i].ToString("X") + ", ";
            }
            richTextBox1.Text += "\n";
        }
        UInt16 cal_crc(byte[] data, int len)
        {
            UInt16 crc = 0xFFFF;
            for (int pos = 0; pos < len; pos++)
            {
                crc ^= data[pos];

                for (int i = 0; i < 8; i++)
                {
                    if ((crc & 0x0001) != 0)
                    {
                        crc >>= 1;
                        crc ^= 0xA001;
                    }
                    else
                    {
                        crc >>= 1;
                    }
                }
            }
            return crc;
        }
        void write_single_coil(UInt16 coil_num, bool state)
        {
            byte[] req = { 0x01, 0x05, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00 };
            if (state == false)
            {
                req[4] = 0x00;
            }

            req[2] = (byte)(coil_num >> 8);
            req[3] = (byte)(coil_num & 0xFF);
            UInt16 crc = cal_crc(req, 6);
            req[6] = (byte)(crc & 0xFF);
            req[7] = (byte)(crc >> 8);
            serialPort1.Write(req, 0, 8);
        }
        private void button4_Click(object sender, EventArgs e)
        {
            if (serialPort1.IsOpen) write_single_coil(1, true);
        }

        private void button5_Click(object sender, EventArgs e)
        {
            if (serialPort1.IsOpen) write_single_coil(1, false);
        }

        private void button6_Click(object sender, EventArgs e)
        {
            if (serialPort1.IsOpen) write_single_coil(2, true);
        }

        private void button7_Click(object sender, EventArgs e)
        {
            if (serialPort1.IsOpen) write_single_coil(2, false);
        }

        private void button8_Click(object sender, EventArgs e)
        {
            if (serialPort1.IsOpen) write_single_coil(3, true);
        }

        private void button9_Click(object sender, EventArgs e)
        {
            if (serialPort1.IsOpen) write_single_coil(3, false);
        }

         private void button10_Click(object sender, EventArgs e)
        {
            if (serialPort1.IsOpen) write_single_coil(4, true);
        }

        private void button11_Click(object sender, EventArgs e)
        {
            if (serialPort1.IsOpen) write_single_coil(4, false);
        }

        private void button12_Click(object sender, EventArgs e)
        {
            if (serialPort1.IsOpen) write_single_coil(5, true);
        }

        private void button13_Click(object sender, EventArgs e)
        {
            if (serialPort1.IsOpen) write_single_coil(5, false);
        }

        private void button14_Click(object sender, EventArgs e)
        {
            if (serialPort1.IsOpen) write_single_coil(6, true);
        }
        private void button15_Click(object sender, EventArgs e)
        {
            if (serialPort1.IsOpen) write_single_coil(6, false);
        }
        private void button16_Click(object sender, EventArgs e)
        {
            if (serialPort1.IsOpen) write_single_coil(7, true);
        }
        private void button17_Click(object sender, EventArgs e)
        {
            if (serialPort1.IsOpen) write_single_coil(7, false);
        }
반응형
Posted by 덕력킹
,