반응형

https://youtube.com/live/sM4WSj0hdWk

[STM32#19] STM32에서 형식이 있는 데이터를 sscanf로 수신하는 방법과 ring buffer 활용방법 알아보기!(녹칸다 내맘대로 STM32)

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

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

STM32에서 sscanf와 ring buffer를 활용해봅시당!

 

1.C#에서 아래와 같은 데이터를 전송할때 STM32가 해석해서 응답을 보낼 수 있도록 sscanf로 기능 구현을 하시오!
(데이터) “num1=1234\n” 일때 STM32는 1234를 추출한다!
(응답) “num1 is 1234!!\n”

/* USER CODE BEGIN 0 */
char rx_buff[100];
char tx_buff[100];
int rx_pos = 0;
char data;
int num1 = 0;
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	//데이터 처리(종료문자가 \n인 상황)
	rx_buff[rx_pos++] = data;
	if(data == '\n'){
		//STM32가 echo
		rx_buff[rx_pos] = '\0';
		//rx_buff에 있는 데이터 형식 num1=1234
		if(sscanf(rx_buff,"num1=%d",&num1) == 1){
			//성공
			sprintf(tx_buff,"num1 is %d!!\n",num1);
			HAL_UART_Transmit(&huart2, tx_buff, strlen(tx_buff), 100);
		}else{
			//실패
			HAL_UART_Transmit(&huart2, "error!\n", 7, 100);
		}
		rx_pos = 0;
	}
	//수신인터럽트 다시 시작
	HAL_UART_Receive_IT(&huart2, &data, 1);
}
private void button1_Click(object sender, EventArgs e)
        {
            serialPort1.PortName = textBox1.Text;
            serialPort1.BaudRate = 115200; //usart2

            serialPort1.Open(); //개방!

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

        private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            string data = serialPort1.ReadLine();
            richTextBox1.Text += "[수신]=" + data + "\n";
        }

        private void button2_Click(object sender, EventArgs e)
        {
            //포트가 열려있고, 입력창이 빈칸이 아닐때~
            if (serialPort1.IsOpen && textBox2.Text != "")
            {
                serialPort1.WriteLine(textBox2.Text);
            }
        }


2.이번에는 아래와같은 커맨드 형식일때 여러개의 명령어를 인식가능하도록 하시오!
(데이터1) “select value = 10”
(데이터2) “update value = 10”
(데이터3) “delete value = 10”
(응답) “cmd is select, value is 10”

/* USER CODE BEGIN 0 */
char rx_buff[100];
char tx_buff[100];
int rx_pos = 0;
char data;
int num1 = 0;
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	//데이터 처리(종료문자가 \n인 상황)
	rx_buff[rx_pos++] = data;
	if(data == '\n'){
		//STM32가 echo
		rx_buff[rx_pos] = '\0';
		//rx_buff에 있는 데이터 형식 “select value = 10”
		if(sscanf(rx_buff,"select value = %d",&num1) == 1){
			//성공
			sprintf(tx_buff,"cmd is select, value is %d\n",num1);
			HAL_UART_Transmit(&huart2, tx_buff, strlen(tx_buff), 100);
		}else if(sscanf(rx_buff,"update value = %d",&num1) == 1){
			//성공
			sprintf(tx_buff,"cmd is update, value is %d\n",num1);
			HAL_UART_Transmit(&huart2, tx_buff, strlen(tx_buff), 100);
		}else if(sscanf(rx_buff,"delete value = %d",&num1) == 1){
			//성공
			sprintf(tx_buff,"cmd is delete, value is %d\n",num1);
			HAL_UART_Transmit(&huart2, tx_buff, strlen(tx_buff), 100);
		}else{
			//실패
			HAL_UART_Transmit(&huart2, "error!\n", 7, 100);
		}
		rx_pos = 0;
	}
	//수신인터럽트 다시 시작
	HAL_UART_Receive_IT(&huart2, &data, 1);
}

 

(C#코드는 예제1과 같음)


3.예제2에서 녹칸다가 제기한 원인을 해결하는 방법에서 약간 다른 방법을 제시해보시오!(여러개의 조건문을 1개로 압축하기)

/* USER CODE BEGIN 0 */
char rx_buff[100];
char tx_buff[100];
int rx_pos = 0;
char data;
int num1 = 0;
char cmd[20];
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	//데이터 처리(종료문자가 \n인 상황)
	rx_buff[rx_pos++] = data;
	if(data == '\n'){
		//STM32가 echo
		rx_buff[rx_pos] = '\0';
		//rx_buff에 있는 데이터 형식 “select value = 10”
		if(sscanf(rx_buff,"%s value = %d",cmd,&num1) == 2){
			//성공
			sprintf(tx_buff,"cmd is %s, value is %d\n",cmd,num1);
			HAL_UART_Transmit(&huart2, tx_buff, strlen(tx_buff), 100);
		}else{
			//실패
			HAL_UART_Transmit(&huart2, "error!\n", 7, 100);
		}
		rx_pos = 0;
	}
	//수신인터럽트 다시 시작
	HAL_UART_Receive_IT(&huart2, &data, 1);
}

 

(C#코드는 예제1과 같음)


4.녹칸다가 아래와 같은 명령어를 입력하면 STM32의 PB3 LED가 제어된다!
(LED OFF) “LED=0”  (LED ON) “LED=1”

/* USER CODE BEGIN 0 */
char rx_buff[100];
char tx_buff[100];
int rx_pos = 0;
char data;
int state = 0;
char cmd[20];
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	//데이터 처리(종료문자가 \n인 상황)
	rx_buff[rx_pos++] = data;
	if(data == '\n'){
		//STM32가 echo
		rx_buff[rx_pos] = '\0';
		//rx_buff에 있는 데이터 형식 "LED=0"
		if(sscanf(rx_buff,"LED=%d",&state) == 1){
			//성공
			if(state == 0){
				HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, state);
				HAL_UART_Transmit(&huart2, "LED IS OFF!\n", 12, 100);
			}else if(state == 1){
				HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, state);
				HAL_UART_Transmit(&huart2, "LED IS ON!\n", 11, 100);
			}
		}else{
			//실패
			HAL_UART_Transmit(&huart2, "error!\n", 7, 100);
		}
		rx_pos = 0;
	}
	//수신인터럽트 다시 시작
	HAL_UART_Receive_IT(&huart2, &data, 1);
}

 

(C#코드는 예제1과 같음)


5.이번에는 예제4와 동일한 구성을 가지면서 STM32쉴드에 붙어있는 LED 8개를 개별적으로 제어할 수 있는 명령어 체계를 구성하시오!
“LED@=%”  : LED번호는 @, ON/OFF여부는 %  (예시) “LED2=1” : LED2번을 ON해라!

/* USER CODE BEGIN 0 */
char rx_buff[100];
char tx_buff[100];
int rx_pos = 0;
char data;
int led_num = 0;
int state = 0;
char cmd[20];
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	//데이터 처리(종료문자가 \n인 상황)
	rx_buff[rx_pos++] = data;
	if(data == '\n'){
		//STM32가 echo
		rx_buff[rx_pos] = '\0';
		//rx_buff에 있는 데이터 형식 "LED@=%"
		if(sscanf(rx_buff,"LED%d=%d",&led_num,&state) == 2){
			//성공
			if(led_num == 1){
				if(state == 0){
					HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, state);
					HAL_UART_Transmit(&huart2, "LED1 IS OFF!\n", 13, 100);
				}else if(state == 1){
					HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, state);
					HAL_UART_Transmit(&huart2, "LED1 IS ON!\n", 12, 100);
				}
			}else if(led_num == 2){
				if(state == 0){
					HAL_GPIO_WritePin(GPIOB, GPIO_PIN_13, state);
					HAL_UART_Transmit(&huart2, "LED2 IS OFF!\n", 13, 100);
				}else if(state == 1){
					HAL_GPIO_WritePin(GPIOB, GPIO_PIN_13, state);
					HAL_UART_Transmit(&huart2, "LED2 IS ON!\n", 12, 100);
				}

			}else if(led_num == 3){
				if(state == 0){
					HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, state);
					HAL_UART_Transmit(&huart2, "LED3 IS OFF!\n", 13, 100);
				}else if(state == 1){
					HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, state);
					HAL_UART_Transmit(&huart2, "LED3 IS ON!\n", 12, 100);
				}
			}else if(led_num == 4){
				if(state == 0){
					HAL_GPIO_WritePin(GPIOB, GPIO_PIN_14, state);
					HAL_UART_Transmit(&huart2, "LED4 IS OFF!\n", 13, 100);
				}else if(state == 1){
					HAL_GPIO_WritePin(GPIOB, GPIO_PIN_14, state);
					HAL_UART_Transmit(&huart2, "LED4 IS ON!\n", 12, 100);
				}
			}else if(led_num == 5){
				if(state == 0){
					HAL_GPIO_WritePin(GPIOB, GPIO_PIN_4, state);
					HAL_UART_Transmit(&huart2, "LED5 IS OFF!\n", 13, 100);
				}else if(state == 1){
					HAL_GPIO_WritePin(GPIOB, GPIO_PIN_4, state);
					HAL_UART_Transmit(&huart2, "LED5 IS ON!\n", 12, 100);
				}
			}else if(led_num == 6){
				if(state == 0){
					HAL_GPIO_WritePin(GPIOB, GPIO_PIN_15, state);
					HAL_UART_Transmit(&huart2, "LED6 IS OFF!\n", 13, 100);
				}else if(state == 1){
					HAL_GPIO_WritePin(GPIOB, GPIO_PIN_15, state);
					HAL_UART_Transmit(&huart2, "LED6 IS ON!\n", 12, 100);
				}

			}else if(led_num == 7){
				if(state == 0){
					HAL_GPIO_WritePin(GPIOC, GPIO_PIN_4, state);
					HAL_UART_Transmit(&huart2, "LED7 IS OFF!\n", 13, 100);
				}else if(state == 1){
					HAL_GPIO_WritePin(GPIOC, GPIO_PIN_4, state);
					HAL_UART_Transmit(&huart2, "LED7 IS ON!\n", 12, 100);
				}
			}else if(led_num == 8){
				if(state == 0){
					HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, state);
					HAL_UART_Transmit(&huart2, "LED8 IS OFF!\n", 13, 100);
				}else if(state == 1){
					HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, state);
					HAL_UART_Transmit(&huart2, "LED8 IS ON!\n", 12, 100);
				}
			}
		}else{
			//실패
			HAL_UART_Transmit(&huart2, "error!\n", 7, 100);
		}
		rx_pos = 0;
	}
	//수신인터럽트 다시 시작
	HAL_UART_Receive_IT(&huart2, &data, 1);
}

 

(C#코드는 예제1과 같음)


6.예제5번에서 코드를 좀 압축해보시오!

/* USER CODE BEGIN 0 */
char rx_buff[100];
char tx_buff[100];
int rx_pos = 0;
char data;
int led_num = 0;
int state = 0;
char cmd[20];
GPIO_TypeDef *mygpio[] = {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};
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	//데이터 처리(종료문자가 \n인 상황)
	rx_buff[rx_pos++] = data;
	if(data == '\n'){
		//STM32가 echo
		rx_buff[rx_pos] = '\0';
		//rx_buff에 있는 데이터 형식 "LED@=%"
		if(sscanf(rx_buff,"LED%d=%d",&led_num,&state) == 2){
			//성공
			if(led_num >=0 && led_num<=8 && (state == 0 || state == 1)){
				HAL_GPIO_WritePin(mygpio[led_num-1], mypin[led_num-1], state);
				sprintf(tx_buff,"LED%d IS %s\n",led_num,state == 0 ? "OFF" : "ON");
				HAL_UART_Transmit(&huart2, tx_buff, strlen(tx_buff), 100);
			}else{
				HAL_UART_Transmit(&huart2, "error-2!\n", 9, 100);
			}
		}else{
			//실패
			HAL_UART_Transmit(&huart2, "error-1!\n", 9, 100);
		}
		rx_pos = 0;
	}
	//수신인터럽트 다시 시작
	HAL_UART_Receive_IT(&huart2, &data, 1);
}

(C#코드는 예제1과 같음)

 

 


7.예제6번에서 동작하는 방식을 JSON명령어를 인식하도록 하시오!
{"led_num":1,"state":0} : LED1 OFF
{"led_num":3,"state":1} : LED3 ON

/* USER CODE BEGIN 0 */
char rx_buff[100];
char tx_buff[100];
int rx_pos = 0;
char data;
int led_num = 0;
int state = 0;
char cmd[20];
GPIO_TypeDef *mygpio[] = {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};
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	//데이터 처리(종료문자가 \n인 상황)
	rx_buff[rx_pos++] = data;
	if(data == '\n'){
		//STM32가 echo
		rx_buff[rx_pos] = '\0';
		//rx_buff에 있는 데이터 형식 "{"led_num":1,"state":0}"
		if(sscanf(rx_buff,"{\"led_num\":%d,\"state\":%d}",&led_num,&state) == 2){
			//성공
			if(led_num >=0 && led_num<=8 && (state == 0 || state == 1)){
				HAL_GPIO_WritePin(mygpio[led_num-1], mypin[led_num-1], state);
				sprintf(tx_buff,"LED%d IS %s\n",led_num,state == 0 ? "OFF" : "ON");
				HAL_UART_Transmit(&huart2, tx_buff, strlen(tx_buff), 100);
			}else{
				HAL_UART_Transmit(&huart2, "error-2!\n", 9, 100);
			}
		}else{
			//실패
			HAL_UART_Transmit(&huart2, "error-1!\n", 9, 100);
		}
		rx_pos = 0;
	}
	HAL_UART_Receive_IT(&huart2, &data, 1);//수신인터럽트 다시 시작
}

 

(C#코드는 예제1과 같음)


8.데이터 형식이 JSON이 되었으니, C#에서도 JSON데이터를 생성할 수 있게 되었다! C#에 JSON라이브러리를 추가해서 조금더 고급스러운 기능을 보이시오!

/* USER CODE BEGIN 0 */
char rx_buff[100];
char tx_buff[100];
int rx_pos = 0;
char data;
int led_num = 0;
int state = 0;
char cmd[20];
GPIO_TypeDef *mygpio[] = {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};
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	//데이터 처리(종료문자가 \n인 상황)
	rx_buff[rx_pos++] = data;
	if(data == '\n'){
		//STM32가 echo
		rx_buff[rx_pos] = '\0';
		//rx_buff에 있는 데이터 형식 "{"led_num":1,"state":0}"
		if(sscanf(rx_buff,"{\"led_num\":%d,\"state\":%d}",&led_num,&state) == 2){
			//성공
			if(led_num >=0 && led_num<=8 && (state == 0 || state == 1)){
				HAL_GPIO_WritePin(mygpio[led_num-1], mypin[led_num-1], state);
				sprintf(tx_buff,"LED%d IS %s\n",led_num,state == 0 ? "OFF" : "ON");
				HAL_UART_Transmit(&huart2, tx_buff, strlen(tx_buff), 100);
			}else{
				HAL_UART_Transmit(&huart2, "error-2!\n", 9, 100);
			}
		}else{
			//실패
			HAL_UART_Transmit(&huart2, "error-1!\n", 9, 100);
		}
		rx_pos = 0;
	}
	HAL_UART_Receive_IT(&huart2, &data, 1);//수신인터럽트 다시 시작
}

 

 

using Newtonsoft.Json;
////////////////////////////////////
//C#의 전역위치
        class Nockanda
        {
            public int led_num;
            public int state;
        }

        Nockanda data = new Nockanda();
/////////////////////////////////////
private void button1_Click(object sender, EventArgs e)
        {
            serialPort1.PortName = textBox1.Text;
            serialPort1.BaudRate = 115200; //usart2

            serialPort1.Open(); //개방!

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

        private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            string data = serialPort1.ReadLine();
            richTextBox1.Text += "[수신]=" + data + "\n";
        }
        void send_data(int led_num, int state)
        {
            if (serialPort1.IsOpen)
            {
                data.led_num = led_num;
                data.state = state;
                string output = JsonConvert.SerializeObject(data);
                serialPort1.WriteLine(output);
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            send_data(1, 1);
        }

        private void button3_Click(object sender, EventArgs e)
        {
            send_data(1, 0);
        }

        private void button4_Click(object sender, EventArgs e)
        {
            send_data(2, 1);
        }

        private void button5_Click(object sender, EventArgs e)
        {
            send_data(2, 0);
        }


        private void button6_Click(object sender, EventArgs e)
        {
            send_data(3, 1);
        }

        private void button7_Click(object sender, EventArgs e)
        {
            send_data(3, 0);
        }

        private void button8_Click(object sender, EventArgs e)
        {
            send_data(4, 1);
        }

        private void button9_Click(object sender, EventArgs e)
        {
            send_data(4, 0);
        }

        private void button10_Click(object sender, EventArgs e)
        {
            send_data(5, 1);
        }

        private void button11_Click(object sender, EventArgs e)
        {
            send_data(5, 0);
        }

        private void button12_Click(object sender, EventArgs e)
        {
            send_data(6, 1);
        }

        private void button13_Click(object sender, EventArgs e)
        {
            send_data(6, 0);
        }

        private void button14_Click(object sender, EventArgs e)
        {
            send_data(7, 1);
        }

        private void button15_Click(object sender, EventArgs e)
        {
            send_data(7, 0);
        }

        private void button16_Click(object sender, EventArgs e)
        {
            send_data(8, 1);
        }

        private void button17_Click(object sender, EventArgs e)
        {
            send_data(8, 0);
        }


9.STM32의 수신인터럽트에서 1개의 문자를 받으면 즉시 응답하도록 해서 putty에서 데이터를 전송하시오!

/* USER CODE BEGIN 0 */
#define b_size 256
uint8_t ring_buffer[b_size];
int head = 0;
int tail = 0;
char data;
char tx_buff[256];
int tx_pos = 0;
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	//수신인터럽트로 받은 데이터를 ring_buffer에 대입한다
	//버퍼에 집어넣는 쪽
	ring_buffer[head++] = data;
	if(head == b_size) head = 0;
	//bad case
	//HAL_UART_Transmit(&huart2, &data, 1, 100);
	//수신인터럽트 다시 시작
	HAL_UART_Receive_IT(&huart2, &data, 1);
}


/* USER CODE BEGIN 2 */
 HAL_UART_Receive_IT(&huart2, &data, 1); //수신인터럽트 시작
 /* USER CODE END 2 */
 /* Infinite loop */
 /* USER CODE BEGIN WHILE */
 while (1)
 {
	  //버퍼에서 읽는 쪽
		if(head != tail){
			tx_buff[tx_pos++] = ring_buffer[tail];
			if(ring_buffer[tail] == '\n'){
				//녹칸다가 보낸 데이터의 끝지점이구나!
				tx_buff[tx_pos] = '\0';
				tx_pos = 0;
				HAL_UART_Transmit(&huart2, tx_buff, strlen(tx_buff), 100);
			}
			tail++;
			if (tail == b_size) tail = 0;
		}
   /* USER CODE END WHILE */
   /* USER CODE BEGIN 3 */
 }
반응형
Posted by 덕력킹
,