2024.1.19
애니메이션으로 0 부터 9까지 숫자를 출력하고 마지막에 하트 출력하기
#include "main.h"
int dotmatrix_main_test(void);
void init_dotmatrix(void);
GPIO_TypeDef *col_port[] =
{
COL1_GPIO_Port, COL2_GPIO_Port, COL3_GPIO_Port, COL4_GPIO_Port,
COL5_GPIO_Port, COL6_GPIO_Port, COL7_GPIO_Port, COL8_GPIO_Port
};
GPIO_TypeDef *row_port[] =
{
ROW1_GPIO_Port, ROW2_GPIO_Port, ROW3_GPIO_Port, ROW4_GPIO_Port,
ROW5_GPIO_Port, ROW6_GPIO_Port, ROW7_GPIO_Port, ROW8_GPIO_Port
};
uint16_t row_pin[] =
{
ROW1_Pin, ROW2_Pin, ROW3_Pin, ROW4_Pin,
ROW5_Pin, ROW6_Pin, ROW7_Pin, ROW8_Pin
};
uint16_t col_pin[] =
{
COL1_Pin, COL2_Pin, COL3_Pin, COL4_Pin,
COL5_Pin, COL6_Pin, COL7_Pin, COL8_Pin
};
const uint8_t blank[8] = {
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000,
0b00000000
};
uint8_t number_data[20][10] =
{
{
0b01110000, //0
0b10001000,
0b10011000,
0b10101000,
0b11001000,
0b10001000,
0b01110000,
0b00000000
},
{
0b01000000, //1
0b11000000,
0b01000000,
0b01000000,
0b01000000,
0b01000000,
0b11100000,
6 // 점 0b00000110
},
{
0b01110000, //2
0b10001000,
0b00001000,
0b00010000,
0b00100000,
0b01000000,
0b11111000,
6
},
{
0b11111000, //3
0b00010000,
0b00100000,
0b00010000,
0b00001000,
0b10001000,
0b01110000,
6
},
{
0b00010000, //4
0b00110000,
0b01010000,
0b10010000,
0b11111000,
0b00010000,
0b00010000,
6
},
{
0b11111000, //5
0b10000000,
0b11110000,
0b00001000,
0b00001000,
0b10001000,
0b01110000,
6
},
{
0b00110000, //6
0b01000000,
0b10000000,
0b11110000,
0b10001000,
0b10001000,
0b01110000,
6
},
{
0b11111000, //7
0b10001000,
0b00001000,
0b00010000,
0b00100000,
0b00100000,
0b00100000,
6
},
{
0b01110000, //8
0b10001000,
0b10001000,
0b01110000,
0b10001000,
0b10001000,
0b01110000,
6
},
{
0b01110000, //9
0b10001000,
0b10001000,
0b01111000,
0b00001000,
0b00010000,
0b01100000,
6
},
{
0b00000000, // heart
0b01100110,
0b11111111,
0b11111111,
0b11111111,
0b01111110,
0b00111100,
0b00011000
}
};
unsigned char display_data[8]; // 최종 8x8 출력할 데이터
unsigned char scroll_buffer[50][8] = {0}; // 스크롤 할 데이터가 들어 있는 버퍼
int number_of_character = 11; // 출력할 문자 개수
// 초기화 작업
// 1. display_data에 number_data[0]에 있는 내용 복사
// 2. number_data를 scroll_buffer에 복사
// 3. dotmatrix의 led를 off
void init_dotmatrix(void)
{
for (int i = 0; i < 8; i++)
{
display_data[i] = number_data[0][i];
}
for (int i = 1; i < number_of_character + 1; i++)
{
for (int j = 0; j < 8; j++)
{
scroll_buffer[i][j] = number_data[i-1][j];
}
}
for (int i = 0; i < 8; i++)
{
HAL_GPIO_WritePin(col_port[i], col_pin[i], 1); // led all off
}
}
void write_column_data(int col)
{
for (int i = 0; i < 8; i++)
{
if (i == col)
HAL_GPIO_WritePin(col_port[i], col_pin[i], 0); // on
else HAL_GPIO_WritePin(col_port[i], col_pin[i], 1); // off
}
}
// 0b00111100
void write_row_data(unsigned char data)
{
unsigned char d; // 오리지널 데이터 변형을 막기 위해
d = data;
for (int i = 0; i < 8; i++)
{
if (d & (1 << i)) // 1인 경우
HAL_GPIO_WritePin(row_port[i], row_pin[i], 1);
else HAL_GPIO_WritePin(row_port[i], row_pin[i], 0);
}
}
// scroll 문자 출력 프로그램
int dotmatrix_main_test(void)
{
static int count = 0; // static으로 지역변수를 전역변수처럼 사용할 수 있음
static int index = 0; // column count, scroll_buffer의 2차원 index 값
static uint32_t past_time = 0; // 이전 tick값 저장
init_dotmatrix();
while(1)
{
uint32_t now = HAL_GetTick(); // 1ms
// 처음 시작 시 past_time = 0;
if (now - past_time >= 500) // 500ms scroll
{
past_time = now;
for (int i = 0; i < 8; i++)
{
display_data[i] = (scroll_buffer[index][i] >> count) | (scroll_buffer[index + 1][i] << 8 - count);
}
if (++count == 8) // 8칼럼을 다 처리 했으면 다음 스크롤 버퍼로 이동
{
count = 0;
index++; // 다음 스크롤 버퍼로 이동
if (index == number_of_character + 1) index = 0;
// 11개의 문자를 다 처리했으면 0번 scroll_buffer를 처리하기 위해 이동한다
}
}
for (int i = 0; i < 8; i++)
{
// 공통 양극 방식 (common anode)
// column에는 0을, row에는 1을 출력해야 해당 LED가 켜진다
write_column_data(i);
write_row_data(display_data[i]);
HAL_Delay(1);
}
}
return 0;
}


스텝 모터가 360도 회전한다
#include "main.h"
#include "button.h"
void set_rpm(int rpm);
void step_motor_main_test(void);
void stepmotor_drive(int step);
extern void delay_us(unsigned long us);
extern int get_button(GPIO_TypeDef *GPIO, uint16_t GPIO_PIN, uint8_t button_number);
/*
RPM (Revolutions Per Minutes) : 분당 회전수
1분 : 60초 : 1,000,000us(1초) x 60 = 60,000,000us
1,000,000us(1초)
--> 1초(1,000ms) => 1ms(1,000us) x 1,000ms ==> 1,000,000us
4096스텝 : 1바퀴(4096스텝 이동)
---> 1바퀴 도는데 필요한 총 스텝 수 : 4096
5096 / 8(0.7) ==> 512 sequence : 360도
1 sequence(8 step) : 0.70312도
0.70312도 x 512 sequence = 360
*/
// ---------- set_rpm(13) 으로 지정 시의 동작 상황 ----------
// 60,000,000us(1분) / 4096 / rpm
// 1126us(1스텝 idle타임) x 4096 = 4,612,096us
// = 4612ms
// = 4.6초
// 60초 / 4.6(1회전 시 소요시간 초) ==> 13회전
void set_rpm(int rpm) // rpm 1 ~ 13
{
delay_us(60000000 / 4096 / rpm);
// 최대 speed 기준(13) : delay_us(1126);
}
// 시계방향으로 1회전 <--> 반시계방향으로 1회전
void step_motor_main_test(void)
{
while(1)
{
for (int i = 0; i < 512; i++) // 시계방향 1회전
{
for (int j = 0; j < 8; j++)
{
stepmotor_drive(j);
set_rpm(13);
}
}
for (int i = 0; i < 512; i++) // 반시계방향 1회전
{
for (int j = 7; j >= 0; j--)
{
stepmotor_drive(j);
set_rpm(13);
}
}
}
}
void stepmotor_drive(int step)
{
switch(step) {
case 0:
HAL_GPIO_WritePin(GPIOD, IN1_Pin, 1);
HAL_GPIO_WritePin(GPIOD, IN2_Pin, 0);
HAL_GPIO_WritePin(GPIOD, IN3_Pin, 0);
HAL_GPIO_WritePin(GPIOD, IN4_Pin, 0);
break;
case 1:
HAL_GPIO_WritePin(GPIOD, IN1_Pin, 1);
HAL_GPIO_WritePin(GPIOD, IN2_Pin, 1);
HAL_GPIO_WritePin(GPIOD, IN3_Pin, 0);
HAL_GPIO_WritePin(GPIOD, IN4_Pin, 0);
break;
case 2:
HAL_GPIO_WritePin(GPIOD, IN1_Pin, 0);
HAL_GPIO_WritePin(GPIOD, IN2_Pin, 1);
HAL_GPIO_WritePin(GPIOD, IN3_Pin, 0);
HAL_GPIO_WritePin(GPIOD, IN4_Pin, 0);
break;
case 3:
HAL_GPIO_WritePin(GPIOD, IN1_Pin, 0);
HAL_GPIO_WritePin(GPIOD, IN2_Pin, 1);
HAL_GPIO_WritePin(GPIOD, IN3_Pin, 1);
HAL_GPIO_WritePin(GPIOD, IN4_Pin, 0);
break;
case 4:
HAL_GPIO_WritePin(GPIOD, IN1_Pin, 0);
HAL_GPIO_WritePin(GPIOD, IN2_Pin, 0);
HAL_GPIO_WritePin(GPIOD, IN3_Pin, 1);
HAL_GPIO_WritePin(GPIOD, IN4_Pin, 0);
break;
case 5:
HAL_GPIO_WritePin(GPIOD, IN1_Pin, 0);
HAL_GPIO_WritePin(GPIOD, IN2_Pin, 0);
HAL_GPIO_WritePin(GPIOD, IN3_Pin, 1);
HAL_GPIO_WritePin(GPIOD, IN4_Pin, 1);
break;
case 6:
HAL_GPIO_WritePin(GPIOD, IN1_Pin, 0);
HAL_GPIO_WritePin(GPIOD, IN2_Pin, 0);
HAL_GPIO_WritePin(GPIOD, IN3_Pin, 0);
HAL_GPIO_WritePin(GPIOD, IN4_Pin, 1);
break;
case 7:
HAL_GPIO_WritePin(GPIOD, IN1_Pin, 1);
HAL_GPIO_WritePin(GPIOD, IN2_Pin, 0);
HAL_GPIO_WritePin(GPIOD, IN3_Pin, 0);
HAL_GPIO_WritePin(GPIOD, IN4_Pin, 1);
break;
}
}
스텝 모터가 멈춘 상태일 때 버튼 1을 누르면 정방향(시계 방향)으로 회전하고, 정방향으로 회전하고 있을 때는 역방향(시계 반대 방향)으로 회전한다.
모터가 돌고 있을 때 버튼 2를 누르면 멈춘다
FSM

// 시계방향으로 1회전 <--> 반시계방향으로 1회전
void step_motor_main_test(void)
{
// 버튼 처리에 의한 스텝 모터
int direction = 0;
while (1)
{
if (get_button(BUTTON0_GPIO_Port, BUTTON0_Pin, 0) == BUTTON_PRESS)
{
if (direction == 0) direction = 1;
else if (direction == 1) direction = 2;
else if (direction == 2) direction= 1;
}
if (get_button(BUTTON1_GPIO_Port, BUTTON1_Pin, 1) == BUTTON_PRESS)
{
if (direction == 1) direction = 0;
else if (direction == 2) direction= 0;
}
stepmotor_drive(direction);
}
}
// direction : 0 => idle
// direction : 1 => 시계 방향 회전
// direction : 2 => 반시계 방향 회전
void stepmotor_drive(int direction)
{
static int step = 0;
switch(step) {
case 0:
HAL_GPIO_WritePin(GPIOD, IN1_Pin, 1);
HAL_GPIO_WritePin(GPIOD, IN2_Pin, 0);
HAL_GPIO_WritePin(GPIOD, IN3_Pin, 0);
HAL_GPIO_WritePin(GPIOD, IN4_Pin, 0);
break;
case 1:
HAL_GPIO_WritePin(GPIOD, IN1_Pin, 1);
HAL_GPIO_WritePin(GPIOD, IN2_Pin, 1);
HAL_GPIO_WritePin(GPIOD, IN3_Pin, 0);
HAL_GPIO_WritePin(GPIOD, IN4_Pin, 0);
break;
case 2:
HAL_GPIO_WritePin(GPIOD, IN1_Pin, 0);
HAL_GPIO_WritePin(GPIOD, IN2_Pin, 1);
HAL_GPIO_WritePin(GPIOD, IN3_Pin, 0);
HAL_GPIO_WritePin(GPIOD, IN4_Pin, 0);
break;
case 3:
HAL_GPIO_WritePin(GPIOD, IN1_Pin, 0);
HAL_GPIO_WritePin(GPIOD, IN2_Pin, 1);
HAL_GPIO_WritePin(GPIOD, IN3_Pin, 1);
HAL_GPIO_WritePin(GPIOD, IN4_Pin, 0);
break;
case 4:
HAL_GPIO_WritePin(GPIOD, IN1_Pin, 0);
HAL_GPIO_WritePin(GPIOD, IN2_Pin, 0);
HAL_GPIO_WritePin(GPIOD, IN3_Pin, 1);
HAL_GPIO_WritePin(GPIOD, IN4_Pin, 0);
break;
case 5:
HAL_GPIO_WritePin(GPIOD, IN1_Pin, 0);
HAL_GPIO_WritePin(GPIOD, IN2_Pin, 0);
HAL_GPIO_WritePin(GPIOD, IN3_Pin, 1);
HAL_GPIO_WritePin(GPIOD, IN4_Pin, 1);
break;
case 6:
HAL_GPIO_WritePin(GPIOD, IN1_Pin, 0);
HAL_GPIO_WritePin(GPIOD, IN2_Pin, 0);
HAL_GPIO_WritePin(GPIOD, IN3_Pin, 0);
HAL_GPIO_WritePin(GPIOD, IN4_Pin, 1);
break;
case 7:
HAL_GPIO_WritePin(GPIOD, IN1_Pin, 1);
HAL_GPIO_WritePin(GPIOD, IN2_Pin, 0);
HAL_GPIO_WritePin(GPIOD, IN3_Pin, 0);
HAL_GPIO_WritePin(GPIOD, IN4_Pin, 1);
break;
}
if (direction == 1) // 시계 방향 회전
{
step++; // for (step = 0; step < 8; step++)
step %= 8; // 다음 진행할 step 준비
set_rpm(13);
}
else if (direction == 2) // 반시계 방향 회전
{
step--;
if (step < 0) step = 7;
set_rpm(10);
}
}
TR(트랜지스터) 용도
포토 인터럽터는 물체의 유무를 감지할 수 있는 소자로,
송신부와 수신부 사이에 물체가 없을 경우 송신부(다이오드)에서 발산한 빛이 포토 트랜지스터를 Turn on 시켜 LOW를 출력한다.
한편 송신부와 수신부 사이에 물체가 들어오게 되면 송신부에서 발산한 빛이 차단되어 포토 트랜지스터가 Turn off가 되어서 HIGH를 출력하게 된다.



기타등등
하드웨어가 소프트웨어한테 알려주는 것이 인터럽트
https://www.rohm.co.kr/electronics-basics/photointerrupters/pi_what2