반응형

https://youtube.com/live/oTKsk64gdPY

[STM32#16] C# winform을 이용해서 STM32f103rb nucleo보드와 usart2로 serial통신하는 방법 계속알아보기!(녹칸다 내맘대로 STM32)

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

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

이제  C#윈폼으로 응용을 해봅시다!

 

1.STM32에서 부호가없는 32bit정수 타입의 값 2개를 1초 간격으로 C#으로 전송한다! 이때 데이터 형식은 CSV 형식이다! C#에서 수신한 데이터를 분리해서 출력하시오!
    -(결과예시) num1은 12345이고, num2는 56789이고, num1+num2는 ???입니다!

/* USER CODE BEGIN 2 */
 uint32_t num1 = 12345;
 uint32_t num2 = 67890;
 char buff[100];
 /* USER CODE END 2 */
 /* Infinite loop */
 /* USER CODE BEGIN WHILE */
 while (1)
 {
	  //num1, num2를 csv형식으로 buff에 대입한다
	  sprintf(buff,"%d,%d\n",num1,num2);
	  //buff안에 있는 값을 널문자(\0)까지의 길이를 반환해서 전송한다
	  HAL_UART_Transmit(&huart2,buff,strlen(buff),100);
	  HAL_Delay(1000);
   /* USER CODE END WHILE */
   /* USER CODE BEGIN 3 */
 }

 

private void button1_Click(object sender, EventArgs e)
        {
            //접속하기 버튼 클릭했다 뭐할래?
            serialPort1.PortName = textBox1.Text;
            serialPort1.BaudRate = 115200;

            //serialport1의 open메서드를 콜한다!
            serialPort1.Open();

            if (serialPort1.IsOpen)
            {
                //버퍼의 직전데이터가 밀려서 들어온다!
                serialPort1.ReadExisting();
                MessageBox.Show("접속완료!");
            }
        }
        private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            //stm32가 데이터를 보냈는데 뭐할래?
            //stm32는 반드시 문자열로 전송하고 종료문자 \n붙힌다!
            string data = serialPort1.ReadLine();
            //STM32가 보낸 데이터는 CSV형식이다!
            string[] csv_data = data.Split(',');
            //STM32가 보낸 데이터는 2개이기 때문에 배열의 갯수는 2여야한다!
            if(csv_data.Length == 2)
            {
                //csv_data[0] : num1
                //csv_data[1] : num2
                UInt32 num1 = UInt32.Parse(csv_data[0]);
                UInt32 num2 = UInt32.Parse(csv_data[1]);
                UInt32 sum = num1 + num2;

                //richTextBox1.Text += "num1=" + num1 + ", num2=" + num2 + ", sum=" + sum + "\n";
                richTextBox1.Text += $"num1={num1}, num2={num2}, sum={sum}\n";
            }
        }


2.예제1번과 동일한 구성인데, STM32가 JSON형식으로 데이터를 전송할때 C#윈폼에서 동일하게 parse해서 richtextbox1에 적절하게 출력하시오!

/* USER CODE BEGIN 2 */
 uint32_t num1 = 12345;
 uint32_t num2 = 67890;
 char buff[100];
 /* USER CODE END 2 */
 /* Infinite loop */
 /* USER CODE BEGIN WHILE */
 while (1)
 {
	  //num1, num2를 csv형식으로 buff에 대입한다
	  sprintf(buff,"{\"num1\":%d, \"num2\":%d}\n",num1,num2);
	  //buff안에 있는 값을 널문자(\0)까지의 길이를 반환해서 전송한다
	  HAL_UART_Transmit(&huart2,buff,strlen(buff),100);
	  HAL_Delay(1000);
   /* USER CODE END WHILE */
   /* USER CODE BEGIN 3 */
 }
using Newtonsoft.Json.Linq; //네임스페이스 추가~

private void button1_Click(object sender, EventArgs e)
        {
            //접속하기 버튼 클릭했다 뭐할래?
            serialPort1.PortName = textBox1.Text;
            serialPort1.BaudRate = 115200;

            //serialport1의 open메서드를 콜한다!
            serialPort1.Open();

            if (serialPort1.IsOpen)
            {
                //버퍼의 직전데이터가 밀려서 들어온다!
                serialPort1.ReadExisting();
                MessageBox.Show("접속완료!");
            }
        }
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            //stm32가 데이터를 보냈는데 뭐할래?
            //stm32는 반드시 문자열로 전송하고 종료문자 \n붙힌다!
            string data = serialPort1.ReadLine();
            //data안에 JSON형식의 데이터가 있다!

            try
            {    
                JObject json_data = JObject.Parse(data);
                UInt32 num1 = UInt32.Parse(json_data["num1"].ToString());// : num1
                UInt32 num2 = UInt32.Parse(json_data["num2"].ToString());// : num2
                UInt32 sum = num1 + num2;

                richTextBox1.Text += $"원본={data}\n";
                richTextBox1.Text += $"num1={num1}, num2={num2}, sum={sum}\n";
            }
            catch
            {
                //만약 json데이터에 문제가 있다면 이쪽으로 떨어짐!
            }
        }


3.이번에는 STM32에서 2개의 숫자 데이터를 바이너리로 전송하는데, 공용체를 이용해서 전송해보시오!

/* USER CODE BEGIN 2 */
 union{
    uint32_t input[2]; //8byte
    uint8_t output[8]; //8byte
 }myunion;
 myunion.input[0] = 12345; //num1
 myunion.input[1] = 67890; //num2
 /* USER CODE END 2 */
 /* Infinite loop */
 /* USER CODE BEGIN WHILE */
 while (1)
 {
	  //공용체에 들어갈때는 32bit정수2개지만, 나올때는 8byte 배열이란다~
	  HAL_UART_Transmit(&huart2,myunion.output,sizeof(myunion.output),100);
	  HAL_Delay(1000);
   /* USER CODE END WHILE */
   /* USER CODE BEGIN 3 */
 }
private void button1_Click(object sender, EventArgs e)
        {
            //접속하기 버튼 클릭했다 뭐할래?
            serialPort1.PortName = textBox1.Text;
            serialPort1.BaudRate = 115200;

            //serialport1의 open메서드를 콜한다!
            serialPort1.Open();

            if (serialPort1.IsOpen)
            {
                //버퍼의 직전데이터가 밀려서 들어온다!
                serialPort1.ReadExisting();
                MessageBox.Show("접속완료!");
            }
        }
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            //stm32가 데이터를 보냈는데 뭐할래?
            //STM32쪽에서 8byte 배열에 날라온다!
            byte[] recv = new byte[8];
            int cnt = 0;
            while (true)
            {
                recv[cnt] = (byte)serialPort1.ReadByte();
                cnt++;
                if (cnt == 8) break;
            }

            //recv배열안에 0~3이 num1, 4~7까지 num2인상황
            UInt32 num1 = BitConverter.ToUInt32(recv, 0);
            UInt32 num2 = BitConverter.ToUInt32(recv, 4);
            UInt32 sum = num1 + num2;

            richTextBox1.Text += $"[수신] = ";
            for (int i = 0; i < 8; i++)
            {
                richTextBox1.Text += recv[i] + ", ";
            }
            richTextBox1.Text += "\n";
            richTextBox1.Text += $"num1={num1}, num2={num2}, sum={sum}\n";

        }


4.예제3과 동일한 구성인데, 이번에는 구조체를 활용해서 전송하시오!(녹칸다 생각에는 이방법이 제일 좋은 방법인듯)

/* USER CODE BEGIN 2 */
 struct{
	 uint32_t num1;
	 uint32_t num2;
 }mystruct;
 mystruct.num1 = 12345;
 mystruct.num2 = 67890;
 /* USER CODE END 2 */
 /* Infinite loop */
 /* USER CODE BEGIN WHILE */
 while (1)
 {
	  HAL_UART_Transmit(&huart2,(uint8_t*)&mystruct,sizeof(mystruct),100);
	  HAL_Delay(1000);
   /* USER CODE END WHILE */
   /* USER CODE BEGIN 3 */
 }
private void button1_Click(object sender, EventArgs e)
        {
            //접속하기 버튼 클릭했다 뭐할래?
            serialPort1.PortName = textBox1.Text;
            serialPort1.BaudRate = 115200;

            //serialport1의 open메서드를 콜한다!
            serialPort1.Open();

            if (serialPort1.IsOpen)
            {
                //버퍼의 직전데이터가 밀려서 들어온다!
                serialPort1.ReadExisting();
                MessageBox.Show("접속완료!");
            }
        }


private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            //stm32가 데이터를 보냈는데 뭐할래?
            //STM32쪽에서 8byte 배열에 날라온다!
            byte[] recv = new byte[8];
            int cnt = 0;
            while (true)
            {
                recv[cnt] = (byte)serialPort1.ReadByte();
                cnt++;
                if (cnt == 8) break;
            }

            //recv배열안에 0~3이 num1, 4~7까지 num2인상황
            UInt32 num1 = BitConverter.ToUInt32(recv, 0);
            UInt32 num2 = BitConverter.ToUInt32(recv, 4);
            UInt32 sum = num1 + num2;

            richTextBox1.Text += $"[수신] = ";
            for (int i = 0; i < 8; i++)
            {
                richTextBox1.Text += recv[i] + ", ";
            }
            richTextBox1.Text += "\n";
            richTextBox1.Text += $"num1={num1}, num2={num2}, sum={sum}\n";

        }


5.녹칸다의 STM32쉴드에 붙어있는 로터리엔코더를 시계방향으로 돌리면 C#윈폼 화면에 값이 1씩 증가하도록하고 반시계방향으로 돌리면 1씩감소하고 스위치를 누르면 0으로 초기화 하도록 하시오!(변화되는 값은 C#의 변수값이다) 

/* USER CODE BEGIN 2 */
 uint8_t old_A = 0;
 /* USER CODE END 2 */
 /* Infinite loop */
 /* USER CODE BEGIN WHILE */
 while (1)
 {
	  uint8_t sw = HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_7);
	  if(sw == 0){
		  HAL_UART_Transmit(&huart2, "0", 1, 100);
		  HAL_Delay(200);
	  }
	  //PA11의 상승엣지가 발생했을때
	  uint8_t now_A = HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_11);
	  if(old_A == 0 && now_A == 1){
		  //PA12의 값을 측정해서 LOW면 시계, HIGH면 반시계
		  uint8_t now_B = HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_12);
		  if(now_B){
			 //반시계
			  HAL_UART_Transmit(&huart2, "-", 1, 100);
		  }else{
			 //시계
			  HAL_UART_Transmit(&huart2, "+", 1, 100);
		  }
	  }
	  old_A = now_A;
	  HAL_Delay(1);
   /* USER CODE END WHILE */
   /* USER CODE BEGIN 3 */
 }
//C#의 전역변수 위치
int cnt = 0;


private void button1_Click(object sender, EventArgs e)
        {
            //접속하기 버튼 클릭했다 뭐할래?
            serialPort1.PortName = textBox1.Text;
            serialPort1.BaudRate = 115200;

            //serialport1의 open메서드를 콜한다!
            serialPort1.Open();

            if (serialPort1.IsOpen)
            {
                //버퍼의 직전데이터가 밀려서 들어온다!
                serialPort1.ReadExisting();
                MessageBox.Show("접속완료!");
            }
        }


private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            //stm32가 데이터를 보냈는데 뭐할래?
            //STM32에서 문자 1개가 수신된다!
            //'+' : 시계방향
            //'-' : 반시계방향
            //'0' : 초기화
            char c = (char)serialPort1.ReadChar();
            richTextBox1.Text += c + "\n";

            if(c == '0')
            {
                cnt = 0;
                textBox2.Text = cnt.ToString();
            }else if (c == '+')
            {
                cnt++;
                textBox2.Text = cnt.ToString();
            }
            else if (c == '-')
            {
                cnt--;
                textBox2.Text = cnt.ToString();
            }
        }


6.예제5에서 로터리엔코더를 돌려서 바뀌는 값은 STM32메모리에 기억되고, 변화되는 값을 C#으로 전송해서 화면에 출력하시오!(카운터값이 -10~+10사이면 흰색, +11부터는 빨간색, -11이하면 노란색으로 바꾸시오!)

/* USER CODE BEGIN 2 */
 int cnt = 0;
 uint8_t old_A = 0;
 char buff[50];
 char recv;
 /* USER CODE END 2 */
 /* Infinite loop */
 /* USER CODE BEGIN WHILE */
 while (1)
 {
	  if(HAL_UART_Receive(&huart2, &recv, 1, 1) == HAL_OK){
		  if(recv == '0'){
			  //C#에서 현재 CNT값을 1회 전송해달라는 명령!
			  sprintf(buff,"%d\n",cnt);
			  HAL_UART_Transmit(&huart2, buff, strlen(buff), 100);
		  }
	  }
	  uint8_t sw = HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_7);
	  if(sw == 0){
		  cnt = 0;
		  sprintf(buff,"%d\n",cnt);
		  HAL_UART_Transmit(&huart2, buff, strlen(buff), 100);
		  HAL_Delay(200);
	  }
	  //PA11의 상승엣지가 발생했을때
	  uint8_t now_A = HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_11);
	  if(old_A == 0 && now_A == 1){
		  //PA12의 값을 측정해서 LOW면 시계, HIGH면 반시계
		  uint8_t now_B = HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_12);
		  if(now_B){
			 //반시계
			  cnt--;
		  }else{
			 //시계
			  cnt++;
		  }
		  sprintf(buff,"%d\n",cnt);
		  HAL_UART_Transmit(&huart2, buff, strlen(buff), 100);
	  }
	  old_A = now_A;
	  HAL_Delay(1);
   /* USER CODE END WHILE */
   /* USER CODE BEGIN 3 */
 }
private void button1_Click(object sender, EventArgs e)
        {
            //접속하기 버튼 클릭했다 뭐할래?
            serialPort1.PortName = textBox1.Text;
            serialPort1.BaudRate = 115200;

            //serialport1의 open메서드를 콜한다!
            serialPort1.Open();

            if (serialPort1.IsOpen)
            {
                //버퍼의 직전데이터가 밀려서 들어온다!
                serialPort1.ReadExisting();
                //C#에서 포트를 개방한 직후 STM32에게 CNT값을 물어본다!
                //STM32에게 문자 '0'을 전송하면 STM32는 응답한다!
                serialPort1.Write("0");
                MessageBox.Show("접속완료!");
            }
        }

private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            //stm32가 데이터를 보냈는데 뭐할래?
            string data = serialPort1.ReadLine();
            textBox2.Text = data;

            int cnt = int.Parse(data);
            if(cnt > 10)
            {
                //빨간색
                textBox2.BackColor = Color.Red;
            }else if(cnt < -11)
            {
                //노란색
                textBox2.BackColor = Color.Yellow;
            }
            else
            {
                //흰색
                textBox2.BackColor = Color.White;
            }
        }


7.예제5에서 로터리엔코더의 스위치를 누르면 0으로 초기화한다라는 조건 대신에, C#윈폼의 listbox를 이용해서 값을 하나씩 추가하는 것을 보이시오!

/* USER CODE BEGIN 2 */
 uint8_t old_A = 0;
 /* USER CODE END 2 */
 /* Infinite loop */
 /* USER CODE BEGIN WHILE */
 while (1)
 {
	  uint8_t sw = HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_7);
	  if(sw == 0){
		  HAL_UART_Transmit(&huart2, "0", 1, 100);
		  HAL_Delay(200);
	  }
	  //PA11의 상승엣지가 발생했을때
	  uint8_t now_A = HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_11);
	  if(old_A == 0 && now_A == 1){
		  //PA12의 값을 측정해서 LOW면 시계, HIGH면 반시계
		  uint8_t now_B = HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_12);
		  if(now_B){
			 //반시계
			  HAL_UART_Transmit(&huart2, "-", 1, 100);
		  }else{
			 //시계
			  HAL_UART_Transmit(&huart2, "+", 1, 100);
		  }
	  }
	  old_A = now_A;
	  HAL_Delay(1);
   /* USER CODE END WHILE */
   /* USER CODE BEGIN 3 */
 }
//C#의 전역변수 위치
int cnt = 0;


private void button1_Click(object sender, EventArgs e)
        {
            //접속하기 버튼 클릭했다 뭐할래?
            serialPort1.PortName = textBox1.Text;
            serialPort1.BaudRate = 115200;

            //serialport1의 open메서드를 콜한다!
            serialPort1.Open();

            if (serialPort1.IsOpen)
            {
                //버퍼의 직전데이터가 밀려서 들어온다!
                serialPort1.ReadExisting();
                MessageBox.Show("접속완료!");
            }
        }



private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            //stm32가 데이터를 보냈는데 뭐할래?
            //STM32에서 문자 1개가 수신된다!
            //'+' : 시계방향
            //'-' : 반시계방향
            //'0' : 초기화
            char c = (char)serialPort1.ReadChar();
            richTextBox1.Text += c + "\n";

            if (c == '0')
            {
                //cnt = 0;
                //textBox2.Text = cnt.ToString();
                //listbox1에 현재 cnt값을 추가함!
                listBox1.Items.Add(cnt);
            }
            else if (c == '+')
            {
                cnt++;
                textBox2.Text = cnt.ToString();
            }
            else if (c == '-')
            {
                cnt--;
                textBox2.Text = cnt.ToString();
            }

        }

        private void button2_Click(object sender, EventArgs e)
        {
            //listbox1에 있는 내용을 다 지운다!
            listBox1.Items.Clear();
        }


8.예제5에서 누겟페키지관리로가서 agauge2를 다운받아서 로터리엔코더로 게이지값을 변화시키시오!

/* USER CODE BEGIN 2 */
 uint8_t old_A = 0;
 /* USER CODE END 2 */
 /* Infinite loop */
 /* USER CODE BEGIN WHILE */
 while (1)
 {
	  uint8_t sw = HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_7);
	  if(sw == 0){
		  HAL_UART_Transmit(&huart2, "0", 1, 100);
		  HAL_Delay(200);
	  }
	  //PA11의 상승엣지가 발생했을때
	  uint8_t now_A = HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_11);
	  if(old_A == 0 && now_A == 1){
		  //PA12의 값을 측정해서 LOW면 시계, HIGH면 반시계
		  uint8_t now_B = HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_12);
		  if(now_B){
			 //반시계
			  HAL_UART_Transmit(&huart2, "-", 1, 100);
		  }else{
			 //시계
			  HAL_UART_Transmit(&huart2, "+", 1, 100);
		  }
	  }
	  old_A = now_A;
	  HAL_Delay(1);
   /* USER CODE END WHILE */
   /* USER CODE BEGIN 3 */
 }
//C#의 전역변수 위치
int cnt = 0;

private void button1_Click(object sender, EventArgs e)
        {
            //접속하기 버튼 클릭했다 뭐할래?
            serialPort1.PortName = textBox1.Text;
            serialPort1.BaudRate = 115200;

            //serialport1의 open메서드를 콜한다!
            serialPort1.Open();

            if (serialPort1.IsOpen)
            {
                //버퍼의 직전데이터가 밀려서 들어온다!
                serialPort1.ReadExisting();
                MessageBox.Show("접속완료!");
            }
        }



private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            //stm32가 데이터를 보냈는데 뭐할래?
            //STM32에서 문자 1개가 수신된다!
            //'+' : 시계방향
            //'-' : 반시계방향
            //'0' : 초기화
            char c = (char)serialPort1.ReadChar();
            richTextBox1.Text += c + "\n";

            if (c == '0')
            {
                cnt = 0;
                textBox2.Text = cnt.ToString();
                aGauge1.Value = cnt;
            }
            else if (c == '+')
            {
                cnt+=5;
                if (cnt > 400) cnt = 400;
                textBox2.Text = cnt.ToString();
                aGauge1.Value = cnt;
            }
            else if (c == '-')
            {
                cnt-=5;
                if (cnt < -100) cnt = -100;
                textBox2.Text = cnt.ToString();
                aGauge1.Value = cnt;
            }

        }
반응형
Posted by 덕력킹
,