printf("ho_tari\n");
13일차 본문
2025.04.08
오늘의 학습 목표
1. step motor 제어
2. ext INT & phto TR
3. thread & mutex (free RTOS)
STEP MOTOR
<stepmotor.c>
/*
* stepmotor.c
*
* Created on: Apr 8, 2025
* Author: microsoft
*/
#include "stepmotor.h"
#include "button.h"
// btn0 : idle(stop)
// btn1 : FW <--> BW
#define IDLE 0
#define FORWARD 1
#define BACKWARD 2
uint8_t stepmotor_state = IDLE;
void set_rpm(int rpm);
void stepmotor_main(void);
int stepmotor_drive(int direction);
/*
* RPM(Revolutions Per Minutes : 분당 최전수
* 1분 60sec : 1sec(1,000,000us) * 60sec : 60,000,000us
* 1초 : 1000ms --> 1ms(1,000us) * 1000ms : 1,000,000us
* 1바퀴 회전 : 4096 step 필요
* 4096 / 8 ==> 512 sequence : 360도 회전
* 1 sequence (8step) : 0.70312도 회전
* 0.70312 x 512 sequence : 360도 회전
* ---- RPM 조절 함수 ----
* 예) 1분에 13회전이 최대 속도
* 13회전 : 60,000,000us(1분) / 4096 step / 13 ==> step과 step간의 간격 time : 1126us
* 1126us x 4096(1회전하는데 필요 step) ==> 4,615,384us
* ==> 4615ms(4.6초)
* 60sec / 4.6sec(1회전하는데 소요 시간) : 13회전
*/
void set_rpm(int rpm) // rmp : 1~13
{
delay_us(60000000/4096/rpm);
// 최대 speed 기준(13) : delay_us(1126);
}
// stepmotor demo
void stepmotor_main(void)
{
#if 1
while(1)
{
switch(stepmotor_state)
{
case IDLE:
if (get_button(GPIOC, BTN1_Pin, BTN1) == BUTTON_PRESS)
{
stepmotor_state = FORWARD;
}
break;
case FORWARD:
stepmotor_drive(FORWARD);
set_rpm(13);
if (get_button(GPIOC, BTN0_Pin, BTN0) == BUTTON_PRESS)
{
stepmotor_state = IDLE;
}
if (get_button(GPIOC, BTN1_Pin, BTN1) == BUTTON_PRESS)
{
stepmotor_state = BACKWARD;
}
break;
case BACKWARD:
stepmotor_drive(BACKWARD);
set_rpm(13);
if (get_button(GPIOC, BTN0_Pin, BTN0) == BUTTON_PRESS)
{
stepmotor_state = IDLE;
}
if (get_button(GPIOC, BTN1_Pin, BTN1) == BUTTON_PRESS)
{
stepmotor_state = FORWARD;
}
break;
}
}
#else // demo
while(1)
{
for (int i = 0; i < 512; i++) // 시계 방향 1회전
{
for (int j = 0; j < 8; j++) // 1 sequence : 8 step
{
stepmotor_drive(j);
set_rpm(13); // 1126us wait
}
}
for (int i = 0; i < 512; i++) // 시계 반대 방향 1회전
{
for (int j = 7; j >= 0; j--) // 1 sequence : 8 step
{
stepmotor_drive(j);
set_rpm(13); // 1126us wait
}
}
}
#endif
}
int stepmotor_drive(int direction)
{
static int step = 0;
switch(step)
{
case 0:
HAL_GPIO_WritePin(GPIOC, IN1_Pin, 1);
HAL_GPIO_WritePin(GPIOC, IN2_Pin, 0);
HAL_GPIO_WritePin(GPIOC, IN3_Pin, 0);
HAL_GPIO_WritePin(GPIOC, IN4_Pin, 0);
break;
case 1:
HAL_GPIO_WritePin(GPIOC, IN1_Pin, 1);
HAL_GPIO_WritePin(GPIOC, IN2_Pin, 1);
HAL_GPIO_WritePin(GPIOC, IN3_Pin, 0);
HAL_GPIO_WritePin(GPIOC, IN4_Pin, 0);
break;
case 2:
HAL_GPIO_WritePin(GPIOC, IN1_Pin, 0);
HAL_GPIO_WritePin(GPIOC, IN2_Pin, 1);
HAL_GPIO_WritePin(GPIOC, IN3_Pin, 0);
HAL_GPIO_WritePin(GPIOC, IN4_Pin, 0);
break;
case 3:
HAL_GPIO_WritePin(GPIOC, IN1_Pin, 0);
HAL_GPIO_WritePin(GPIOC, IN2_Pin, 1);
HAL_GPIO_WritePin(GPIOC, IN3_Pin, 1);
HAL_GPIO_WritePin(GPIOC, IN4_Pin, 0);
break;
case 4:
HAL_GPIO_WritePin(GPIOC, IN1_Pin, 0);
HAL_GPIO_WritePin(GPIOC, IN2_Pin, 0);
HAL_GPIO_WritePin(GPIOC, IN3_Pin, 1);
HAL_GPIO_WritePin(GPIOC, IN4_Pin, 0);
break;
case 5:
HAL_GPIO_WritePin(GPIOC, IN1_Pin, 0);
HAL_GPIO_WritePin(GPIOC, IN2_Pin, 0);
HAL_GPIO_WritePin(GPIOC, IN3_Pin, 1);
HAL_GPIO_WritePin(GPIOC, IN4_Pin, 1);
break;
case 6:
HAL_GPIO_WritePin(GPIOC, IN1_Pin, 0);
HAL_GPIO_WritePin(GPIOC, IN2_Pin, 0);
HAL_GPIO_WritePin(GPIOC, IN3_Pin, 0);
HAL_GPIO_WritePin(GPIOC, IN4_Pin, 1);
break;
case 7:
HAL_GPIO_WritePin(GPIOC, IN1_Pin, 1);
HAL_GPIO_WritePin(GPIOC, IN2_Pin, 0);
HAL_GPIO_WritePin(GPIOC, IN3_Pin, 0);
HAL_GPIO_WritePin(GPIOC, IN4_Pin, 1);
break;
}
if (direction == FORWARD)
{
step++;
step %= 8; // 다음 진행할 step for (i = 0; i < 512; i++)
}
else // BACKWARD
{
step--;
if (step < 0) // for (j = 7; j < 0; j--)
{
step = 7;
}
}
}
<stepmotor.h>
/*
* stepmotor.h
*
* Created on: Apr 8, 2025
* Author: microsoft
*/
#ifndef INC_STEPMOTOR_H_
#define INC_STEPMOTOR_H_
#include "main.h"
#endif /* INC_STEPMOTOR_H_ */
<실행 결과>
https://youtube.com/shorts/CKdQhFPf18k
포토 센서 (포토 인터럽트)
투과형 포토 센서는 발관 소자와 수광 소자를 1개의 패키지에 마주보도록 배열하고, 그 사이를 검출물이 통과할 때 빛이 차단되는 현상을 통해 물체의 유무를 검출하는 과아 스위치, 투과형 포토 센서를 포토 인터럽트라고 한다.
포토 인터럽트는 물체의 유무를 감지할 수 있는 소자로 송신부와 수신부 사이에 물체가 없을 경우 송신부(다이오드)에서 발산한 빛이 포토 트랜지스터를 Turn on 시켜 LOW를 출력한다. 그러나 송신부와 수신부 사이에 물체가 들어오게 되면 송신부에서 발산한 빛이 차단되어 포토 트랜지스터가 tURN OFF가 되어서 HIGH를 출력하게 된다.
EXT INT
<stepmotor.c>
/*
* stepmotor.c
*
* Created on: Apr 8, 2025
* Author: microsoft
*/
#include "stepmotor.h"
#include "button.h"
volatile uint8_t stepmotor_state = IDLE;
void set_rpm(int rpm);
void stepmotor_main(void);
int stepmotor_drive(int direction);
/*
* RPM(Revolutions Per Minutes : 분당 최전수
* 1분 60sec : 1sec(1,000,000us) * 60sec : 60,000,000us
* 1초 : 1000ms --> 1ms(1,000us) * 1000ms : 1,000,000us
* 1바퀴 회전 : 4096 step 필요
* 4096 / 8 ==> 512 sequence : 360도 회전
* 1 sequence (8step) : 0.70312도 회전
* 0.70312 x 512 sequence : 360도 회전
* ---- RPM 조절 함수 ----
* 예) 1분에 13회전이 최대 속도
* 13회전 : 60,000,000us(1분) / 4096 step / 13 ==> step과 step간의 간격 time : 1126us
* 1126us x 4096(1회전하는데 필요 step) ==> 4,615,384us
* ==> 4615ms(4.6초)
* 60sec / 4.6sec(1회전하는데 소요 시간) : 13회전
*/
void set_rpm(int rpm) // rmp : 1~13
{
delay_us(60000000/4096/rpm);
// 최대 speed 기준(13) : delay_us(1126);
}
// stepmotor demo
void stepmotor_main(void)
{
#if 1
while(1)
{
switch(stepmotor_state)
{
case IDLE:
if (get_button(GPIOC, BTN1_Pin, BTN1) == BUTTON_PRESS)
{
stepmotor_state = FORWARD;
}
break;
case FORWARD:
stepmotor_drive(FORWARD);
set_rpm(13);
if (get_button(GPIOC, BTN0_Pin, BTN0) == BUTTON_PRESS)
{
stepmotor_state = IDLE;
}
if (get_button(GPIOC, BTN1_Pin, BTN1) == BUTTON_PRESS)
{
stepmotor_state = BACKWARD;
}
break;
case BACKWARD:
stepmotor_drive(BACKWARD);
set_rpm(13);
if (get_button(GPIOC, BTN0_Pin, BTN0) == BUTTON_PRESS)
{
stepmotor_state = IDLE;
}
if (get_button(GPIOC, BTN1_Pin, BTN1) == BUTTON_PRESS)
{
stepmotor_state = FORWARD;
}
break;
}
}
#else // demo
while(1)
{
for (int i = 0; i < 512; i++) // 시계 방향 1회전
{
for (int j = 0; j < 8; j++) // 1 sequence : 8 step
{
stepmotor_drive(j);
set_rpm(13); // 1126us wait
}
}
for (int i = 0; i < 512; i++) // 시계 반대 방향 1회전
{
for (int j = 7; j >= 0; j--) // 1 sequence : 8 step
{
stepmotor_drive(j);
set_rpm(13); // 1126us wait
}
}
}
#endif
}
int stepmotor_drive(int direction)
{
static int step = 0;
switch(step)
{
case 0:
HAL_GPIO_WritePin(GPIOC, IN1_Pin, 1);
HAL_GPIO_WritePin(GPIOC, IN2_Pin, 0);
HAL_GPIO_WritePin(GPIOC, IN3_Pin, 0);
HAL_GPIO_WritePin(GPIOC, IN4_Pin, 0);
break;
case 1:
HAL_GPIO_WritePin(GPIOC, IN1_Pin, 1);
HAL_GPIO_WritePin(GPIOC, IN2_Pin, 1);
HAL_GPIO_WritePin(GPIOC, IN3_Pin, 0);
HAL_GPIO_WritePin(GPIOC, IN4_Pin, 0);
break;
case 2:
HAL_GPIO_WritePin(GPIOC, IN1_Pin, 0);
HAL_GPIO_WritePin(GPIOC, IN2_Pin, 1);
HAL_GPIO_WritePin(GPIOC, IN3_Pin, 0);
HAL_GPIO_WritePin(GPIOC, IN4_Pin, 0);
break;
case 3:
HAL_GPIO_WritePin(GPIOC, IN1_Pin, 0);
HAL_GPIO_WritePin(GPIOC, IN2_Pin, 1);
HAL_GPIO_WritePin(GPIOC, IN3_Pin, 1);
HAL_GPIO_WritePin(GPIOC, IN4_Pin, 0);
break;
case 4:
HAL_GPIO_WritePin(GPIOC, IN1_Pin, 0);
HAL_GPIO_WritePin(GPIOC, IN2_Pin, 0);
HAL_GPIO_WritePin(GPIOC, IN3_Pin, 1);
HAL_GPIO_WritePin(GPIOC, IN4_Pin, 0);
break;
case 5:
HAL_GPIO_WritePin(GPIOC, IN1_Pin, 0);
HAL_GPIO_WritePin(GPIOC, IN2_Pin, 0);
HAL_GPIO_WritePin(GPIOC, IN3_Pin, 1);
HAL_GPIO_WritePin(GPIOC, IN4_Pin, 1);
break;
case 6:
HAL_GPIO_WritePin(GPIOC, IN1_Pin, 0);
HAL_GPIO_WritePin(GPIOC, IN2_Pin, 0);
HAL_GPIO_WritePin(GPIOC, IN3_Pin, 0);
HAL_GPIO_WritePin(GPIOC, IN4_Pin, 1);
break;
case 7:
HAL_GPIO_WritePin(GPIOC, IN1_Pin, 1);
HAL_GPIO_WritePin(GPIOC, IN2_Pin, 0);
HAL_GPIO_WritePin(GPIOC, IN3_Pin, 0);
HAL_GPIO_WritePin(GPIOC, IN4_Pin, 1);
break;
}
if (direction == FORWARD)
{
step++;
step %= 8; // 다음 진행할 step for (i = 0; i < 512; i++)
}
else // BACKWARD
{
step--;
if (step < 0) // for (j = 7; j < 0; j--)
{
step = 7;
}
}
}
<extint.c>
/*
* extint.c
*
* Created on: Apr 8, 2025
* Author: microsoft
*/
#include "extint.h"
#include "stepmotor.h"
extern volatile uint8_t stepmotor_state;
/**
* move from Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_gpio.c to here
* external INT callback function
* @brief EXTI line detection callbacks.
* @param GPIO_Pin Specifies the pins connected EXTI line
* @retval None
*/
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
switch(GPIO_Pin)
{
case GPIO_PIN_0: // PC0 / BTN0
stepmotor_state = IDLE;
printf("GPIO_PIN_0\n");
break;
case GPIO_PIN_4: //PC4 / BTN1
if (stepmotor_state == IDLE)
{
stepmotor_state = FORWARD;
}
else if (stepmotor_state == FORWARD)
{
stepmotor_state = BACKWARD;
}
else if (stepmotor_state == BACKWARD)
{
stepmotor_state = FORWARD;
}
printf("GPIO_PIN_4\n");
break;
}
}
<extint.h>
/*
* extint.h
*
* Created on: Apr 8, 2025
* Author: microsoft
*/
#ifndef INC_EXTINT_H_
#define INC_EXTINT_H_
#include "main.h"
#endif /* INC_EXTINT_H_ */
<실행 결과>
Thread
<main.c>
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART2_UART_Init();
MX_TIM11_Init();
MX_TIM2_Init();
MX_I2C1_Init();
MX_TIM3_Init();
MX_TIM5_Init();
/* USER CODE BEGIN 2 */
i2c_lcd_init();
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10 | GPIO_PIN_13 | GPIO_PIN_15, 0);
HAL_Delay(10); // DOTMATRIX init
HAL_UART_Receive_IT(&huart2, &rx_data, 1);
HAL_TIM_Base_Start_IT(&htim11);
HAL_TIM_Base_Start_IT(&htim2); // for make delay_us
// stepmotor_main();
// dotmatrix_main_func();
// dotmatrix_main_test();
// servo_motor_main();
// buzzer_main();
// i2c_lcd_main();
// ds1302_main();
// led_main();
// dht11_main();
/* USER CODE END 2 */
/* Init scheduler */
osKernelInitialize();
/* USER CODE BEGIN RTOS_MUTEX */
/* add mutexes, ... */
/* USER CODE END RTOS_MUTEX */
/* USER CODE BEGIN RTOS_SEMAPHORES */
/* add semaphores, ... */
/* USER CODE END RTOS_SEMAPHORES */
/* USER CODE BEGIN RTOS_TIMERS */
/* start timers, add new ones, ... */
/* USER CODE END RTOS_TIMERS */
/* USER CODE BEGIN RTOS_QUEUES */
/* add queues, ... */
/* USER CODE END RTOS_QUEUES */
/* Create the thread(s) */
/* creation of defaultTask */
defaultTaskHandle = osThreadNew(StartDefaultTask, NULL, &defaultTask_attributes);
/* creation of myTask02 */
myTask02Handle = osThreadNew(StartTask02, NULL, &myTask02_attributes);
/* creation of myTask03 */
myTask03Handle = osThreadNew(StartTask03, NULL, &myTask03_attributes);
/* USER CODE BEGIN RTOS_THREADS */
/* add threads, ... */
/* USER CODE END RTOS_THREADS */
/* USER CODE BEGIN RTOS_EVENTS */
/* add events, ... */
/* USER CODE END RTOS_EVENTS */
/* Start scheduler */
osKernelStart();
/* We should never get here as control is now taken by the scheduler */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
// button_led_toggle_test();
// HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
// HAL_Delay(500);
// HAL_GPIO_WritePin(GPIOB, 0Xff, 1);
// HAL_Delay(500);
// HAL_GPIO_WritePin(GPIOB, 0Xff, 0);
// HAL_Delay(500);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/* USER CODE BEGIN Header_StartTask02 */
/**
* @brief Function implementing the myTask02 thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartTask02 */
void StartTask02(void *argument)
{
/* USER CODE BEGIN StartTask02 */
/* Infinite loop */
for(;;)
{
dotmatrix_main_test();
osDelay(1);
}
/* USER CODE END StartTask02 */
}
/* USER CODE BEGIN Header_StartTask03 */
/**
* @brief Function implementing the myTask03 thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartTask03 */
void StartTask03(void *argument)
{
/* USER CODE BEGIN StartTask03 */
/* Infinite loop */
for(;;)
{
stepmotor_main();
osDelay(1);
}
/* USER CODE END StartTask03 */
}
<dotmatrix.c>
void dotmatrix_main_test()
{
uint8_t temp;
static int i = 0;
#if 1
col[0] = ~(1 << i); // 00000001 --> 11111110
col[1] = smile[i];
// HAL_SPI_Transmit(&hspi2, col, 2, 1);
for (int j = 0; j < 2; j++)
{
for (int k = 0; k < 8; k++)
{
temp = col[j];
if (temp & (1 << k))
{
HAL_GPIO_WritePin(GPIOB, SER_74HC595_Pin, 1);
}
else
{
HAL_GPIO_WritePin(GPIOB, SER_74HC595_Pin, 0);
}
HAL_GPIO_WritePin(GPIOB, CLK_74HC595_Pin, 1); // clk을 상승에서
HAL_GPIO_WritePin(GPIOB, CLK_74HC595_Pin, 0); // 하강으로
}
}
GPIOB->ODR &= ~GPIO_PIN_13; // latch핀을 pull-down
GPIOB->ODR |= GPIO_PIN_13; // latch핀을 pull-up
i++;
i %= 8; // 다음 진행할 step for(i = 0; i < 8; i++)
#endif
#if 0
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10 | GPIO_PIN_13 | GPIO_PIN_15, 0);
HAL_Delay(10);
while (1)
{
for (int i=0; i < 8; i++)
{
col[0] = ~(1 << i); // 00000001 --> 11111110
col[1] = hart[i];
// HAL_SPI_Transmit(&hspi2, col, 2, 1);
for (int j = 0; j < 2; j++)
{
for (int k = 0; k < 8; k++)
{
temp = col[j];
if (temp & (1 << k))
{
HAL_GPIO_WritePin(GPIOB, SER_74HC595_Pin, 1);
}
else
{
HAL_GPIO_WritePin(GPIOB, SER_74HC595_Pin, 0);
}
HAL_GPIO_WritePin(GPIOB, CLK_74HC595_Pin, 1); // clk을 상승에서
HAL_GPIO_WritePin(GPIOB, CLK_74HC595_Pin, 0); // 하강으로
}
}
GPIOB->ODR &= ~GPIO_PIN_13; // latch핀을 pull-down
GPIOB->ODR |= GPIO_PIN_13; // latch핀을 pull-up
HAL_Delay(1);
}
}
#endif
}
'(Telechips) AI 시스템 반도체 SW 개발자 교육 > STM32CubeIDE' 카테고리의 다른 글
14일차 (0) | 2025.04.09 |
---|---|
9일차 (0) | 2025.04.04 |
8일차 (0) | 2025.04.03 |
7일차 (0) | 2025.04.02 |
6일차 (0) | 2025.04.01 |