반응형

https://youtube.com/live/g8DphoILqS0

[STM32#33] 블루필보드로 3D프린터개발산업기사 실기 공개문제에 있는 메뉴트리 구현과 스탭모터(nema17 & a4988) 제어 구현해보기!(녹칸다 내맘대로 STM32)

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

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

3D프린터개발산업기사에 있는 일부 내용을 STM32보드로 한번 접근해보는 것입니다!
실제 시험은 아두이노 메가로 하니 실기 시험과 전혀 관련없습니당

 

1.PB5,PB6,PB7핀을 활용해서 로터리엔코더를 연결하고 선형적인 링크드 리스트를 구성해서 로터리 엔코더를 돌렸을때 항목이 바뀌는 결과를 PC의 putty 화면에 하시오!

/* USER CODE BEGIN 2 */
 uint8_t buff[50];
 uint8_t old_A = 0;
 typedef struct Node {
    struct Node *parent;
    struct Node *child;
    int value;
 }Node;
 Node n1; //최상위
 Node n2;
 Node n3;
 Node n4; //최하위
 //n1의 자식은 n2이고 부모는 없다!
 n1.value = 1;
 n1.child = &n2;
 n1.parent = NULL;
 //n2의 자식은 n3이고 부모는 n1이다!
 n2.value = 2;
 n2.child = &n3;
 n2.parent = &n1;
 //n3의 자식은 n4이고 부모는 n2이다!
 n3.value = 3;
 n3.child = &n4;
 n3.parent = &n2;
 //n4의 자식은 없고 부모는 n3이다!
 n4.value = 4;
 n4.child = NULL;
 n4.parent = &n3;
 //초기 관심노드는 n1이다!
 Node *CWD = &n1;
 int num = 0;
 /* USER CODE END 2 */

while (1)
 {
	  //녹칸다가 풀업방식으로 연결해놓음
	  uint8_t sw = HAL_GPIO_ReadPin(rot_sw_GPIO_Port,rot_sw_Pin);
	  if(sw == 0){
		  //현재 CWD가 참조하는 원본의 num값이 몇이냐?
		  sprintf(buff,"num = %d\n",CWD->value);
		  CDC_Transmit_FS(buff, strlen(buff));
		  HAL_Delay(200);
	  }
	  //PA11의 상승엣지가 발생했을때
	  uint8_t now_A = HAL_GPIO_ReadPin(rot_clk_GPIO_Port,rot_clk_Pin);
	  if(old_A == 0 && now_A == 1){
		  //PA12의 값을 측정해서 LOW면 시계, HIGH면 반시계
		  uint8_t now_B = HAL_GPIO_ReadPin(rot_dt_GPIO_Port,rot_dt_Pin);
		  if(now_B){
			 //반시계
			  //최하위 -> 최상위 방향으로 이동
			  //만약 부모노드가 없다면 이동하지 않는다!
			  if(CWD->parent){
				  CWD = CWD->parent;
			  }else{
				  CDC_Transmit_FS("THIS NODE IS ROOT!\n", 19);
			  }
			  sprintf(buff,"num = %d\n",CWD->value);
			  CDC_Transmit_FS(buff, strlen(buff));

		  }else{
			 //시계
			  //최상위 -> 최하위 방향이동
			  //만약 자식노드가 없다면 이동하지 않는다!
			  if(CWD->child){
				  CWD = CWD->child;
			  }else{
				  CDC_Transmit_FS("THIS NODE IS LEAF!\n", 19);
			  }
			  sprintf(buff,"num = %d\n",CWD->value);
			  CDC_Transmit_FS(buff, strlen(buff));
		  }
	  }
	  old_A = now_A;
	  HAL_Delay(1);
   /* USER CODE END WHILE */
   /* USER CODE BEGIN 3 */
 }


2.공개시험 문제에 나오는 메뉴트리를 그대로 구성하되 결과를 PC 화면에서 출력하시오!

/* USER CODE BEGIN 2 */
 uint8_t buff[50];
 uint8_t old_A = 0;
 typedef struct Node {
    struct Node *parent;
    struct Node *child;
    struct Node *next;
    struct Node *prev;
    uint8_t Text[20];
    uint8_t is_return; //true면 리턴노드
 }Node;
 Node root;
 Node menu1;
 Node menu2;
 Node menu2_1;
 Node menu2_2;
 strcpy(menu1.Text, "EXIT            ");
 strcpy(menu2.Text, "MOTOR TEST      ");
 strcpy(menu2_1.Text, "ANGLE:+000.0    ");
 strcpy(menu2_2.Text, "RETURN          ");
 root.is_return = 0;
 menu1.is_return = 1;
 menu2.is_return = 0;
 menu2_1.is_return = 0;
 menu2_2.is_return = 1;
 root.parent = NULL;
 root.child = &menu1;
 root.next = NULL;
 root.prev = NULL;

 menu1.parent = &root;
 menu1.child = NULL;
 menu1.next = &menu2;
 menu1.prev = &menu2;
 menu2.parent = &root;
 menu2.child = &menu2_1;
 menu2.next = &menu1;
 menu2.prev = &menu1;
 menu2_1.parent = &menu2;
 menu2_1.child = NULL;
 menu2_1.next = &menu2_2;
 menu2_1.prev = NULL;
 menu2_2.parent = &menu2;
 menu2_2.child = NULL;
 menu2_2.next = NULL;
 menu2_2.prev = &menu2_1;
 Node *CWD = &root;
 //초기화면은 root의 화면이 출력된다!
 CDC_Transmit_FS("X:    Y:    A000\n3D PRINTER READY\n", 34);
 /* USER CODE END 2 */


while (1)
 {
	  //녹칸다가 풀업방식으로 연결해놓음
	  uint8_t sw = HAL_GPIO_ReadPin(rot_sw_GPIO_Port,rot_sw_Pin);
	  if(sw == 0){
		  //현재노드가 root노드이면 root의 하위메뉴로 진입한다!
		  if(CWD == &root){
			  CWD = CWD->child;
			  //LCD에 나와야할 내용은 child와 그다음 삼촌이다!
			  //>CWD->Text;
			  // CWD->next->Text;
			  CDC_Transmit_FS(">", 1);
			  HAL_Delay(10);
			  CDC_Transmit_FS(CWD->Text, strlen(CWD->Text));
			  HAL_Delay(10);
			  CDC_Transmit_FS("\n ", 2);
			  HAL_Delay(10);
			  CDC_Transmit_FS(CWD->next->Text, strlen(CWD->next->Text));
			  HAL_Delay(10);
			  CDC_Transmit_FS("\n", 1);
		  }else{
			  //만약에 현재 노드가 리턴노드면 상위메뉴로 이동한다
			  if(CWD->is_return){
				  if(CWD->parent){
					  CWD = CWD->parent;
					  //상위메뉴로 올라갔는데, 그 메뉴가 root인 경우

					  if(CWD == &root){
						  //root 고유한 화면 출력
						  CDC_Transmit_FS("X:    Y:    A000\n3D PRINTER READY\n", 34);
					  }else{
						  CDC_Transmit_FS(">", 1);
						  HAL_Delay(10);
						  CDC_Transmit_FS(CWD->Text, strlen(CWD->Text));
						  HAL_Delay(10);
						  CDC_Transmit_FS("\n ", 2);
						  HAL_Delay(10);
						  CDC_Transmit_FS(CWD->next->Text, strlen(CWD->next->Text));
						  HAL_Delay(10);
						  CDC_Transmit_FS("\n", 1);
					  }
				  }
			  }else{
				  //루트도 아니고 리턴노드도 아니라면 하위메뉴로 진입한다!
				  if(CWD->child){
					  CWD = CWD->child;
					  CDC_Transmit_FS(">", 1);
					  HAL_Delay(10);
					  CDC_Transmit_FS(CWD->Text, strlen(CWD->Text));
					  HAL_Delay(10);
					  CDC_Transmit_FS("\n ", 2);
					  HAL_Delay(10);

					  CDC_Transmit_FS(CWD->next->Text, strlen(CWD->next->Text));
					  HAL_Delay(10);
					  CDC_Transmit_FS("\n", 1);
				  }else{
					  //리프노드인 경우
				  }
			  }
		  }
		  HAL_Delay(200);
	  }
	  //PA11의 상승엣지가 발생했을때
	  uint8_t now_A = HAL_GPIO_ReadPin(rot_clk_GPIO_Port,rot_clk_Pin);
	  if(old_A == 0 && now_A == 1){
		  //PA12의 값을 측정해서 LOW면 시계, HIGH면 반시계
		  uint8_t now_B = HAL_GPIO_ReadPin(rot_dt_GPIO_Port,rot_dt_Pin);
		  if(now_B){
			 //반시계
			  if(CWD != &root && CWD->prev){
				 CWD = CWD->prev;
				 //*CWD->text
				 // CWD->next->text
				 CDC_Transmit_FS(">", 1);
				  HAL_Delay(10);
				  CDC_Transmit_FS(CWD->Text, strlen(CWD->Text));
				  HAL_Delay(10);
				  CDC_Transmit_FS("\n ", 2);
				  HAL_Delay(10);
				  CDC_Transmit_FS(CWD->next->Text, strlen(CWD->next->Text));

				  HAL_Delay(10);
				  CDC_Transmit_FS("\n", 1);
			 }
		  }else{
			 //시계
			 //만약 next로 갈게 있다면 next로 이동한다!
			 if(CWD != &root && CWD->next){
				 CWD = CWD->next;
				 // CWD->prev->text
				 //*CWD->text
				 CDC_Transmit_FS(" ", 1);
				  HAL_Delay(10);
				  CDC_Transmit_FS(CWD->prev->Text, strlen(CWD->prev->Text));
				  HAL_Delay(10);
				  CDC_Transmit_FS("\n>", 2);
				  HAL_Delay(10);
				  CDC_Transmit_FS(CWD->Text, strlen(CWD->Text));
				  HAL_Delay(10);
				  CDC_Transmit_FS("\n", 1);
			 }
		  }
	  }
	  old_A = now_A;
	  HAL_Delay(1);
   /* USER CODE END WHILE */
   /* USER CODE BEGIN 3 */
 }


3.예제 2의 결과를 1602LCD 화면에 출력하시오! 

#define delay_ms HAL_Delay
#define SYS_CLOCK    72
#define SYSTICK_LOAD 72000-1
uint32_t millis_cnt = 0;
uint32_t millis() {
 return millis_cnt;
}
uint32_t micros() {
 return (millis_cnt & 0x3FFFFF) * 1000 + (SYSTICK_LOAD - SysTick->VAL) / SYS_CLOCK;
}
void delay_us(uint32_t us) {  // 64MHz 보정
 if (us > 1) {
   uint32_t count = us * 7 - 6;
   while (count--);
 } else {
   uint32_t count = 2;
   while (count--);
 }
}
#define ADDRESS   0x27<<1
#define RS1_EN1   0x05
#define RS1_EN0   0x01
#define RS0_EN1   0x04
#define RS0_EN0   0x00
#define BackLight 0x08
// RS-Q0 / RW-Q1 / EN-Q2 / BackLight-Q3 / D4-Q4 / D5-Q5 / D6-Q6 / D7-Q7
void LCD_DATA(uint8_t data) {
 uint8_t temp=(data & 0xF0)|RS1_EN1|BackLight;
 while(HAL_I2C_Master_Transmit(&hi2c1, ADDRESS, &temp, 1, 1000)!=HAL_OK);
 temp=(data & 0xF0)|RS1_EN0|BackLight;
 while(HAL_I2C_Master_Transmit(&hi2c1, ADDRESS, &temp, 1, 1000)!=HAL_OK);
 delay_us(4);
 temp=((data << 4) & 0xF0)|RS1_EN1|BackLight;
 while(HAL_I2C_Master_Transmit(&hi2c1, ADDRESS, &temp, 1, 1000)!=HAL_OK);
 temp = ((data << 4) & 0xF0)|RS1_EN0|BackLight;
 while(HAL_I2C_Master_Transmit(&hi2c1, ADDRESS, &temp, 1, 1000)!=HAL_OK);
 delay_us(50);
}
void LCD_CMD(uint8_t cmd) {
 uint8_t temp=(cmd & 0xF0)|RS0_EN1|BackLight;
 while(HAL_I2C_Master_Transmit(&hi2c1, ADDRESS, &temp, 1, 1000)!=HAL_OK);
 temp=(cmd & 0xF0)|RS0_EN0|BackLight;
 while(HAL_I2C_Master_Transmit(&hi2c1, ADDRESS, &temp, 1, 1000)!=HAL_OK);
 delay_us(4);
 temp=((cmd << 4) & 0xF0)|RS0_EN1|BackLight;
 while(HAL_I2C_Master_Transmit(&hi2c1, ADDRESS, &temp, 1, 1000)!=HAL_OK);
 temp=((cmd << 4) & 0xF0)|RS0_EN0|BackLight;
 while(HAL_I2C_Master_Transmit(&hi2c1, ADDRESS, &temp, 1, 1000)!=HAL_OK);
 delay_us(50);
}
void LCD_CMD_4bit(uint8_t cmd) {
 uint8_t temp=((cmd << 4) & 0xF0)|RS0_EN1|BackLight;
 while(HAL_I2C_Master_Transmit(&hi2c1, ADDRESS, &temp, 1, 1000)!=HAL_OK);
 temp=((cmd << 4) & 0xF0)|RS0_EN0|BackLight;
 while(HAL_I2C_Master_Transmit(&hi2c1, ADDRESS, &temp, 1, 1000)!=HAL_OK);
 delay_us(50);
}
void LCD_INIT(void) {
 delay_ms(100);
 LCD_CMD_4bit(0x03); delay_ms(5);
 LCD_CMD_4bit(0x03); delay_us(100);
 LCD_CMD_4bit(0x03); delay_us(100);
 LCD_CMD_4bit(0x02); delay_us(100);
 LCD_CMD(0x28);  // 4 bits, 2 line, 5x8 font
 LCD_CMD(0x08);  // display off, cursor off, blink off
 LCD_CMD(0x01);  // clear display
 delay_ms(3);
 LCD_CMD(0x06);  // cursor movint direction
 LCD_CMD(0x0C);  // display on, cursor off, blink off
}
void LCD_XY(char x, char y) {
 if      (y == 0) LCD_CMD(0x80 + x);
 else if (y == 1) LCD_CMD(0xC0 + x);
 else if (y == 2) LCD_CMD(0x94 + x);
 else if (y == 3) LCD_CMD(0xD4 + x);
}
void LCD_CLEAR(void) {
 LCD_CMD(0x01);
 delay_ms(2);
}
void LCD_PUTS(char *str) {
 while (*str) LCD_DATA(*str++);
}
/* USER CODE BEGIN 2 */
 LCD_INIT(); //1회호출(메인루프 시작전)
 uint8_t buff[50];
 uint8_t old_A = 0;
 typedef struct Node {
    struct Node *parent;
    struct Node *child;
    struct Node *next;
    struct Node *prev;
    uint8_t Text[20];
    uint8_t is_return; //true면 리턴노드
 }Node;
 Node root;
 Node menu1;
 Node menu2;
 Node menu2_1;
 Node menu2_2;
 strcpy(menu1.Text, "EXIT            ");
 strcpy(menu2.Text, "MOTOR TEST      ");
 strcpy(menu2_1.Text, "ANGLE:+000.0    ");
 strcpy(menu2_2.Text, "RETURN          ");
 root.is_return = 0;
 menu1.is_return = 1;
 menu2.is_return = 0;
 menu2_1.is_return = 0;
 menu2_2.is_return = 1;
 root.parent = NULL;
 root.child = &menu1;
 root.next = NULL;
 root.prev = NULL;

 menu1.parent = &root;
 menu1.child = NULL;
 menu1.next = &menu2;
 menu1.prev = &menu2;
 menu2.parent = &root;
 menu2.child = &menu2_1;
 menu2.next = &menu1;
 menu2.prev = &menu1;
 menu2_1.parent = &menu2;
 menu2_1.child = NULL;
 menu2_1.next = &menu2_2;
 menu2_1.prev = NULL;
 menu2_2.parent = &menu2;
 menu2_2.child = NULL;
 menu2_2.next = NULL;
 menu2_2.prev = &menu2_1;
 Node *CWD = &root;
 //초기화면은 root의 화면이 출력된다!
 LCD_XY(0, 0) ; LCD_PUTS("X:    Y:    A000");
 LCD_XY(0, 1) ; LCD_PUTS("3D PRINTER READY");
 /* USER CODE END 2 */


while (1)
 {
	  //녹칸다가 풀업방식으로 연결해놓음
	  uint8_t sw = HAL_GPIO_ReadPin(rot_sw_GPIO_Port,rot_sw_Pin);
	  if(sw == 0){
		  //현재노드가 root노드이면 root의 하위메뉴로 진입한다!
		  if(CWD == &root){
			  CWD = CWD->child;
			  //LCD에 나와야할 내용은 child와 그다음 삼촌이다!
			  //>CWD->Text;
			  // CWD->next->Text;
			  LCD_XY(0, 0) ; LCD_PUTS(">");
			  LCD_XY(1, 0) ; LCD_PUTS(CWD->Text);
			  LCD_XY(0, 1) ; LCD_PUTS(" ");
			  LCD_XY(1, 1) ; LCD_PUTS(CWD->next->Text);
		  }else{
			  //만약에 현재 노드가 리턴노드면 상위메뉴로 이동한다
			  if(CWD->is_return){
				  if(CWD->parent){
					  CWD = CWD->parent;
					  //상위메뉴로 올라갔는데, 그 메뉴가 root인 경우
					  if(CWD == &root){
						  //root 고유한 화면 출력
						  LCD_XY(0, 0) ; LCD_PUTS("X:    Y:    A000");
						  LCD_XY(0, 1) ; LCD_PUTS("3D PRINTER READY");
					  }else{
						  LCD_XY(0, 0) ; LCD_PUTS(">");
						  LCD_XY(1, 0) ; LCD_PUTS(CWD->Text);
						  LCD_XY(0, 1) ; LCD_PUTS(" ");
						  LCD_XY(1, 1) ; LCD_PUTS(CWD->next->Text);
					  }
				  }
			  }else{
				  //루트도 아니고 리턴노드도 아니라면 하위메뉴로 진입한다!
				  if(CWD->child){
					  CWD = CWD->child;
					  LCD_XY(0, 0) ; LCD_PUTS(">");
					  LCD_XY(1, 0) ; LCD_PUTS(CWD->Text);
					  LCD_XY(0, 1) ; LCD_PUTS(" ");
					  LCD_XY(1, 1) ; LCD_PUTS(CWD->next->Text);
				  }else{
					  //리프노드인 경우
				  }
			  }
		  }
		  HAL_Delay(200);
	  }
	  //PA11의 상승엣지가 발생했을때
	  uint8_t now_A = HAL_GPIO_ReadPin(rot_clk_GPIO_Port,rot_clk_Pin);
	  if(old_A == 0 && now_A == 1){
		  //PA12의 값을 측정해서 LOW면 시계, HIGH면 반시계
		  uint8_t now_B = HAL_GPIO_ReadPin(rot_dt_GPIO_Port,rot_dt_Pin);
		  if(now_B){
			 //반시계
			  if(CWD != &root && CWD->prev){
				 CWD = CWD->prev;
				 LCD_XY(0, 0) ; LCD_PUTS(">");
				 LCD_XY(1, 0) ; LCD_PUTS(CWD->Text);
				 LCD_XY(0, 1) ; LCD_PUTS(" ");
				 LCD_XY(1, 1) ; LCD_PUTS(CWD->next->Text);
			 }

		  }else{
			 //시계
			 //만약 next로 갈게 있다면 next로 이동한다!
			 if(CWD != &root && CWD->next){
				 CWD = CWD->next;
				 LCD_XY(0, 0) ; LCD_PUTS(" ");
				 LCD_XY(1, 0) ; LCD_PUTS(CWD->prev->Text);
				 LCD_XY(0, 1) ; LCD_PUTS(">");
				 LCD_XY(1, 1) ; LCD_PUTS(CWD->Text);
			 }
		  }
	  }
	  old_A = now_A;
	  HAL_Delay(1);
   /* USER CODE END WHILE */
   /* USER CODE BEGIN 3 */
 }


4.PB3핀에 A4988의 STEP핀을 연결하고 PB4에 DIR핀을 연결해서 NEMA17스탭모터를 테스트 하는 코드를 먼저 만드시오! 로터리엔코더 스위치를 누르면 시계방향으로 계속회전하고 한번더 누르면 멈추도록 하시오! 에서 그냥 최종 결과를 바로 반영하시오!

#define delay_ms HAL_Delay
#define SYS_CLOCK    72
#define SYSTICK_LOAD 72000-1
uint32_t millis_cnt = 0;
uint32_t millis() {
 return millis_cnt;
}
uint32_t micros() {
 return (millis_cnt & 0x3FFFFF) * 1000 + (SYSTICK_LOAD - SysTick->VAL) / SYS_CLOCK;
}
void delay_us(uint32_t us) {  // 64MHz 보정
 if (us > 1) {
   uint32_t count = us * 7 - 6;
   while (count--);
 } else {
   uint32_t count = 2;
   while (count--);
 }
}
#define ADDRESS   0x27<<1
#define RS1_EN1   0x05
#define RS1_EN0   0x01
#define RS0_EN1   0x04
#define RS0_EN0   0x00
#define BackLight 0x08
// RS-Q0 / RW-Q1 / EN-Q2 / BackLight-Q3 / D4-Q4 / D5-Q5 / D6-Q6 / D7-Q7
void LCD_DATA(uint8_t data) {
 uint8_t temp=(data & 0xF0)|RS1_EN1|BackLight;
 while(HAL_I2C_Master_Transmit(&hi2c1, ADDRESS, &temp, 1, 1000)!=HAL_OK);
 temp=(data & 0xF0)|RS1_EN0|BackLight;
 while(HAL_I2C_Master_Transmit(&hi2c1, ADDRESS, &temp, 1, 1000)!=HAL_OK);
 delay_us(4);
 temp=((data << 4) & 0xF0)|RS1_EN1|BackLight;
 while(HAL_I2C_Master_Transmit(&hi2c1, ADDRESS, &temp, 1, 1000)!=HAL_OK);
 temp = ((data << 4) & 0xF0)|RS1_EN0|BackLight;
 while(HAL_I2C_Master_Transmit(&hi2c1, ADDRESS, &temp, 1, 1000)!=HAL_OK);
 delay_us(50);
}
void LCD_CMD(uint8_t cmd) {
 uint8_t temp=(cmd & 0xF0)|RS0_EN1|BackLight;
 while(HAL_I2C_Master_Transmit(&hi2c1, ADDRESS, &temp, 1, 1000)!=HAL_OK);
 temp=(cmd & 0xF0)|RS0_EN0|BackLight;
 while(HAL_I2C_Master_Transmit(&hi2c1, ADDRESS, &temp, 1, 1000)!=HAL_OK);
 delay_us(4);
 temp=((cmd << 4) & 0xF0)|RS0_EN1|BackLight;
 while(HAL_I2C_Master_Transmit(&hi2c1, ADDRESS, &temp, 1, 1000)!=HAL_OK);
 temp=((cmd << 4) & 0xF0)|RS0_EN0|BackLight;
 while(HAL_I2C_Master_Transmit(&hi2c1, ADDRESS, &temp, 1, 1000)!=HAL_OK);
 delay_us(50);
}
void LCD_CMD_4bit(uint8_t cmd) {
 uint8_t temp=((cmd << 4) & 0xF0)|RS0_EN1|BackLight;
 while(HAL_I2C_Master_Transmit(&hi2c1, ADDRESS, &temp, 1, 1000)!=HAL_OK);
 temp=((cmd << 4) & 0xF0)|RS0_EN0|BackLight;
 while(HAL_I2C_Master_Transmit(&hi2c1, ADDRESS, &temp, 1, 1000)!=HAL_OK);
 delay_us(50);
}
void LCD_INIT(void) {
 delay_ms(100);
 LCD_CMD_4bit(0x03); delay_ms(5);
 LCD_CMD_4bit(0x03); delay_us(100);
 LCD_CMD_4bit(0x03); delay_us(100);
 LCD_CMD_4bit(0x02); delay_us(100);
 LCD_CMD(0x28);  // 4 bits, 2 line, 5x8 font
 LCD_CMD(0x08);  // display off, cursor off, blink off
 LCD_CMD(0x01);  // clear display
 delay_ms(3);
 LCD_CMD(0x06);  // cursor movint direction
 LCD_CMD(0x0C);  // display on, cursor off, blink off
}
void LCD_XY(char x, char y) {
 if      (y == 0) LCD_CMD(0x80 + x);
 else if (y == 1) LCD_CMD(0xC0 + x);
 else if (y == 2) LCD_CMD(0x94 + x);
 else if (y == 3) LCD_CMD(0xD4 + x);
}
void LCD_CLEAR(void) {
 LCD_CMD(0x01);
 delay_ms(2);
}
void LCD_PUTS(char *str) {
 while (*str) LCD_DATA(*str++);
}
/* USER CODE BEGIN 0 */
volatile int32_t set_deg = 0;
int32_t now_deg = 0;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(set_deg*2 > now_deg){
		//시계방향으로 회전해서 목표지점에 도달한다!
		HAL_GPIO_WritePin(DIR_GPIO_Port, DIR_Pin, 0); //정회전
		HAL_GPIO_TogglePin(STEP_GPIO_Port, STEP_Pin);
		now_deg++;
	}else if(set_deg*2 < now_deg){
		//반시계방향으로 회전해서 목표지점에 도달한다!
		HAL_GPIO_WritePin(DIR_GPIO_Port, DIR_Pin, 1); //역회전
		HAL_GPIO_TogglePin(STEP_GPIO_Port, STEP_Pin);
		now_deg--;
	}
}
/* USER CODE END 0 */
/* USER CODE BEGIN 2 */
 HAL_TIM_Base_Start_IT(&htim3);
 HAL_GPIO_WritePin(DIR_GPIO_Port, DIR_Pin, 0); //회전방향
 LCD_INIT(); //1회호출(메인루프 시작전)
 uint8_t buff[50];
 uint8_t old_A = 0;
 typedef struct Node {
    struct Node *parent;
    struct Node *child;
    struct Node *next;
    struct Node *prev;
    uint8_t Text[20];
    uint8_t is_return; //true면 리턴노드
 }Node;
 Node root;
 Node menu1;
 Node menu2;
 Node menu2_1;
 Node menu2_2;
 strcpy(menu1.Text, "EXIT            ");
 strcpy(menu2.Text, "MOTOR TEST      ");
 strcpy(menu2_1.Text, "ANGLE:+000.0    ");
 strcpy(menu2_2.Text, "RETURN          ");
 root.is_return = 0;
 menu1.is_return = 1;
 menu2.is_return = 0;
 menu2_1.is_return = 0;
 menu2_2.is_return = 1;
 root.parent = NULL;
 root.child = &menu1;
 root.next = NULL;
 root.prev = NULL;
 menu1.parent = &root;
 menu1.child = NULL;
 menu1.next = &menu2;
 menu1.prev = &menu2;
 menu2.parent = &root;
 menu2.child = &menu2_1;
 menu2.next = &menu1;
 menu2.prev = &menu1;
 menu2_1.parent = &menu2;
 menu2_1.child = NULL;
 menu2_1.next = &menu2_2;
 menu2_1.prev = NULL;
 menu2_2.parent = &menu2;
 menu2_2.child = NULL;
 menu2_2.next = NULL;
 menu2_2.prev = &menu2_1;
 Node *CWD = &root;
 //초기화면은 root의 화면이 출력된다!
 LCD_XY(0, 0) ; LCD_PUTS("X:    Y:    A000");
 LCD_XY(0, 1) ; LCD_PUTS("3D PRINTER READY");
 float target_deg = 0;
 int32_t tar_deg = 0;
 /* USER CODE END 2 */
while (1)
 {
	  //녹칸다가 풀업방식으로 연결해놓음
	  uint8_t sw = HAL_GPIO_ReadPin(rot_sw_GPIO_Port,rot_sw_Pin);
	  if(sw == 0){
		  //현재노드가 root노드이면 root의 하위메뉴로 진입한다!
		  if(CWD == &root){
			  CWD = CWD->child;
			  //LCD에 나와야할 내용은 child와 그다음 삼촌이다!
			  //>CWD->Text;
			  // CWD->next->Text;
			  LCD_XY(0, 0) ; LCD_PUTS(">");
			  LCD_XY(1, 0) ; LCD_PUTS(CWD->Text);
			  LCD_XY(0, 1) ; LCD_PUTS(" ");
			  LCD_XY(1, 1) ; LCD_PUTS(CWD->next->Text);
		  }else{
			  //만약에 현재 노드가 리턴노드면 상위메뉴로 이동한다
			  if(CWD->is_return){
				  if(CWD->parent){
					  CWD = CWD->parent;
					  //상위메뉴로 올라갔는데, 그 메뉴가 root인 경우
					  if(CWD == &root){
						  //root 고유한 화면 출력
						  LCD_XY(0, 0) ; LCD_PUTS("X:    Y:    A000");
						  LCD_XY(0, 1) ; LCD_PUTS("3D PRINTER READY");

					  }else{
						  LCD_XY(0, 0) ; LCD_PUTS(">");
						  LCD_XY(1, 0) ; LCD_PUTS(CWD->Text);
						  LCD_XY(0, 1) ; LCD_PUTS(" ");
						  LCD_XY(1, 1) ; LCD_PUTS(CWD->next->Text);
					  }
				  }
			  }else{
				  //루트도 아니고 리턴노드도 아니라면 하위메뉴로 진입한다!
				  if(CWD->child){
					  CWD = CWD->child;
					  LCD_XY(0, 0) ; LCD_PUTS(">");
					  LCD_XY(1, 0) ; LCD_PUTS(CWD->Text);
					  LCD_XY(0, 1) ; LCD_PUTS(" ");
					  LCD_XY(1, 1) ; LCD_PUTS(CWD->next->Text);
				  }else{
					  //리프노드인 경우
					  if(CWD == &menu2_1){
						  //한번 누르면 설정 한번더 누르면 확인
						  HAL_Delay(200);
						  while(1){
							  uint8_t now_A = HAL_GPIO_ReadPin(rot_clk_GPIO_Port,rot_clk_Pin);
							  if(old_A == 0 && now_A == 1){
								  //PA12의 값을 측정해서 LOW면 시계, HIGH면 반시계
								  uint8_t now_B = HAL_GPIO_ReadPin(rot_dt_GPIO_Port,rot_dt_Pin);

								  if(now_B){
									 //반시계
									  target_deg -= 1.8;
									  tar_deg--;
									  LCD_XY(0, 0) ; LCD_PUTS(">");
									  sprintf(CWD->Text,"ANGLE:%.1f       ",target_deg);
									  LCD_XY(1, 0) ; LCD_PUTS(CWD->Text);
								  }else{
									 //시계
									  target_deg += 1.8;
									  tar_deg++;
									  LCD_XY(0, 0) ; LCD_PUTS(">");
									  sprintf(CWD->Text,"ANGLE:%.1f       ",target_deg);
									  LCD_XY(1, 0) ; LCD_PUTS(CWD->Text);
								  }
							  }
							  old_A = now_A;
							  HAL_Delay(1);
							  //버튼을 한번 누르면 무한루프
							  //한번더 누르면 종료
							  if(HAL_GPIO_ReadPin(rot_sw_GPIO_Port,rot_sw_Pin) == 0){
								  //녹칸다가 설정한 값으로 스탭모터를 회전시키기!
								  set_deg = tar_deg;
								  HAL_Delay(200);
								  break;
							  }
						  }
					  }

				  }
			  }
		  }
		  HAL_Delay(200);
	  }
	  //PA11의 상승엣지가 발생했을때
	  uint8_t now_A = HAL_GPIO_ReadPin(rot_clk_GPIO_Port,rot_clk_Pin);
	  if(old_A == 0 && now_A == 1){
		  //PA12의 값을 측정해서 LOW면 시계, HIGH면 반시계
		  uint8_t now_B = HAL_GPIO_ReadPin(rot_dt_GPIO_Port,rot_dt_Pin);
		  if(now_B){
			 //반시계
			  if(CWD != &root && CWD->prev){
				 CWD = CWD->prev;
				 LCD_XY(0, 0) ; LCD_PUTS(">");
				 LCD_XY(1, 0) ; LCD_PUTS(CWD->Text);
				 LCD_XY(0, 1) ; LCD_PUTS(" ");
				 LCD_XY(1, 1) ; LCD_PUTS(CWD->next->Text);
			 }
		  }else{
			 //시계
			 //만약 next로 갈게 있다면 next로 이동한다!
			 if(CWD != &root && CWD->next){
				 CWD = CWD->next;
				 LCD_XY(0, 0) ; LCD_PUTS(" ");
				 LCD_XY(1, 0) ; LCD_PUTS(CWD->prev->Text);
				 LCD_XY(0, 1) ; LCD_PUTS(">");
				 LCD_XY(1, 1) ; LCD_PUTS(CWD->Text);

			 }
		  }
	  }
	  old_A = now_A;
	  HAL_Delay(1);
   /* USER CODE END WHILE */
   /* USER CODE BEGIN 3 */
 }
반응형
Posted by 덕력킹
,