๐ ์ค์ต ๋ชฉํ
1. PC - MCU Uart Polling & Interrupt ๋๊ฐ์ง ๋ฐฉ์ ๋ฌธ์์ด ์ก์์ ํ
์คํธ
2. PC - MCU Uart ํต์ ์ฐ๊ฒฐ์ ์ํ uart.c ํ์ผ ์์ฑ
3. Command Line Interface (CLI)์ ๊ธฐ๋ฅ ๊ตฌํ์ ์ํ cli.c ํ์ผ ์์ฑ
4. ์ํํ ๋์ led.c, pwm.c ํ์ผ ์์ฑ
๐ Uart ์ธํ
์ฌ๊ธฐ์ USART๋ ๊ฐ์ข
ํต์ ํ๋กํ ์ฝ(e.g. UART, SPI, I2C ๋ฑ..)์ ๊ตฌํํ๊ณ ์๋น์คํ๋ ํฌํธ์ด์ง USART ํต์ ์ด ์๋๋ค.
1. UART ์ธํ
1.1 Word Length
ํ ๋ฒ์ ๋ฐ์ดํฐ ์ ์ก์์ ์ฌ์ฉํ ์ ์๋ ๋นํธ ์๋ฅผ ์ค์ 8๋นํธ์ด๋ฉด 0๋ถํฐ 255๊น์ง์ ๊ฐ์ด๋ฏ๋ก ๋๋ถ๋ถ์ ๊ฐ์ ํํํ ์
์์ผ๋ฉฐ ๋ ๋ฎ๊ฑฐ๋ ๋ ๋์ ๊ฒฝ์ฐ ํธํ์ฑ, ํจ์จ์ฑ ๋ฑ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์์ด 8๋นํธ๋ฅผ ์ฌ์ฉํ๋ค.
1.2 Parity
์ ์กํ ๋ฐ์ดํฐ bit ์๊ฐ ์ง์, ํ์ ์ธ์ง๋ฅผ ๋งจ ๋ ๋นํธ๋ฅผ ํตํด ํ์ํ์ฌ ์์ ์ ์ง์ ํ์ ๋ง๋์ง ํ์ธ
1.3 Data Direction
ํด๋น MCU๋ก๋ถํฐ ๋ฐ์ดํฐ๊ฐ ํ๋ฌ๊ฐ๋ ๋ฐฉํฅ์ ์ค์ ํ๋ฉฐ ์ก์ , ์์ , ์ก/์์ ์ค ํ๋๋ฅผ ์ ํํ๋ค.
1.4 Over Sampling
์ก/์์ ์ ์ ํ๋๋ฅผ ๋์ด๋ ๋ฐ ์ฌ์ฉ๋๋ฉฐ ๋ณดํต 16๋ฐฐ๋ฅผ ์ฌ์ฉํ๋ค.
2. ๋ฐ์ดํฐ ์ํธ์ ์ ํ์๋ ๋๋ก PD8 ํ -> TX ํ์ผ๋ก, PD9 ํ -> RX ํ์ผ๋ก ์ธํ
ํ์์ผ๋ฉฐ
3. USART3 ์ System Core NVIC์์ ์ธํฐ๋ฝํธ ์ก์์ ์ ์ํ Global interrupt๋ฅผ Enable๋ก ์ธํ
ํ์์
๐ ์ค์ต ๊ฒฐ๊ณผ
ใ https://github.com/Tobbyvv/stm32-project/tree/main/uart_cli
PC - MCU Uart Polling & Interrupt ๋ฐฉ์์ผ๋ก ๋ฌธ์์ด ์ก์์ ํ ์คํธ
1.1 Polling ๋ฐฉ์
uint8_t text = 'Hello';
while(1)
{ //1. MCU์์ ์์ (Receive) ์ฑ๊ณต ์ ๋ฐ์ํ๋ HAL_OK ์ ํธ๋ฅผ while ๋ฌธ์ ํตํด ๋ฌดํํ ์ฒดํฌ
if(HAL_UART_Receive(&huart3, &text, 1, 10) == HAL_OK){
//2. ์์ ์ฑ๊ณต ์ ๋ฐ์ ๋ฉ์ธ์ง๋ฅผ PC๋ก ์ก์ (Transmit)
HAL_UART_Transmit(&huart3, &text, 1, 10);
}}
1.2 Interrupt ๋ฐฉ์
uint8_t rx_buffer;
//์ธํฐ๋ฝํธ ๋ฐ์ ์ ํ๋ ์์
์ ๋ฉ์ถ๊ณ ํด๋น ๋ฉ์๋๊ฐ ์คํ๋จ
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if(huart->Instance==USART3){
//IT : ๋น ๋ธ๋กํน(์์ ๋๊ธฐ ์ค ๋์์ ํด์ผํ ๋ค๋ฅธ ์์
์ํ)
HAL_UART_Receive_IT(&huart3, &rx3_data, 1);
//์ธํฐ๋ฝํธ(it) ์์ ํจ์, 1byte๊ฐ ๋ค์ด์ฌ ๋๋ง๋ค ํ์ธํจ
HAL_UART_Transmit(&huart3, &rx3_data, 1, 10);
//๋ค์ด์จ ๋ฐ์ดํฐ๋ฅผ 1byte ์ฉ ๋ณด๋ธ๋ค.
}}
PC - MCU Uart ํต์ ์ ์ํ uart.c ํ์ผ ์์ฑ
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdbool.h>
#include "main.h"
#include "uart.h"
#include "cli.h"
extern UART_HandleTypeDef huart3; // UART ํต์ ํธ๋ค๋ฌ ์ ์ธ
#define D_BUF_MAX 100 // ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ ๋ฒํผ์ ์ต๋ ํฌ๊ธฐ ์ ์
// ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ ๊ตฌ์กฐ์ฒด ์ ์
typedef struct {
uint8_t buf[D_BUF_MAX+1]; // ๋ฐ์ดํฐ ๋ฒํผ ๋ณ์
uint8_t idx; // ๋ฒํผ ์ธ๋ฑ์ค ๋ณ์
uint8_t flag; // ์์ ์๋ฃ ํ๋๊ทธ
} BUF_T;
BUF_T gBufObj[2]; // ๋ ๊ฐ์ ๋ฒํผ ๊ตฌ์กฐ์ฒด ๋ฐฐ์ด๋ก ์ ์ธ
static UART_CBF uart_cbf; // UART ์์ ์ฝ๋ฐฑ ํจ์ ํฌ์ธํฐ ์ ์ธ
uint8_t rxd; // ์์ ํ ๋ฐ์ดํธ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ ๋ณ์
void uart_init(void)
{
gBufObj[0].idx = 0;
gBufObj[0].flag = false;
// UART ์์ ์ธํฐ๋ฝํธ ํ์ฑํ ๋ฐ ์ฒซ ๋ฒ์งธ ๋ฐ์ดํธ(๋ฐ์ํฐ) ์์ ๋๊ธฐ
HAL_UART_Receive_IT(&huart3, (uint8_t *)&rxd, 1);
printf("UART Initialized...\r\n");
fflush(stdout); // printf ํ ์ถ๋ ฅ ๋ฒํผ ๋น์
}
// UART ์์ ์ฝ๋ฐฑ ํจ์ ๋ฑ๋ก
void uart_regcbf(UART_CBF cbf)
{
uart_cbf = cbf; // ์ ๋ฌ๋ ์ฝ๋ฐฑ ํจ์๋ฅผ uart_cbf์ ๋ฑ๋ก
}
// UART ์์ ๋ ๋ฐ์ดํฐ ์ฒ๋ฆฌ ํจ์
void uart_proc(void)
{
BUF_T *p = (BUF_T *)&gBufObj[0];
if (p->flag == true) {
printf("%s:%s", __func__, p->buf); // ๋๋ฒ๊น
์ฉ ์์ ๋ ๋ฐ์ดํฐ ์ถ๋ ฅ
if (uart_cbf != NULL) uart_cbf(p->buf); // UART ๋ฐ์ดํฐ ํ์ฑ ํจ์ ํธ์ถ (๋ฑ๋ก๋ ์ฝ๋ฐฑ ํจ์)
p->idx = 0; // ๋ค์ ๋ฐ์ดํฐ ์์ ์ ์ํ ๋ฒํผ ์ธ๋ฑ์ค ์ด๊ธฐํ
p->flag = false; // ์์ ์๋ฃ ํ๋๊ทธ ์ด๊ธฐํ
}}
// UART ์์ ์๋ฃ ์ฝ๋ฐฑ ํจ์
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart == &huart3) {
BUF_T *p = (BUF_T *)&gBufObj[0];
if (p->flag == false) {
p->buf[p->idx] = rxd; // ์์ ํ ๋ฐ์ดํฐ๋ฅผ ๋ฒํผ์ ์ ์ฅ
if (p->idx < D_BUF_MAX) {
p->idx++; // ๋ฒํผ ์ธ๋ฑ์ค ์ฆ๊ฐ
}
if (rxd == '\r' || rxd == '\n') {
p->buf[p->idx] = '\0'; // ์์ ๋ฐ์ดํฐ์ ๋์ NULL ๋ฌธ์ ์ถ๊ฐ
p->flag = true; // ์์ ์๋ฃ ํ๋๊ทธ ์ค์
}}
uart_proc(); // ์์ ๋ ๋ฐ์ดํฐ ์ฒ๋ฆฌ ํจ์ ํธ์ถ
HAL_UART_Receive_IT(&huart3, (uint8_t *)&rxd, 1); // ๋ค์ ์์ ๋๊ธฐ
}}
// UART ํ์ค ์
์ถ๋ ฅ ํจ์
int __io_putchar(int ch)
{
HAL_UART_Transmit(&huart3, (uint8_t *)&ch, 1, 0xffff); // ๋ฌธ์ ์ ์ก
return ch;
}
Command Line Interface (CLI)์ ๊ธฐ๋ฅ ๊ตฌํ์ ์ํ cli.c ํ์ผ ์์ฑ
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdbool.h>
#include <string.h>
#include "main.h"
#include "uart.h"
#include "led.h"
#include "pwm.h"
#include "cli.h"
#define D_DELIMITER " ,\r\n" //๊ณต๋ฐฑ, ์ผํ, ๊ตฌ๋ถ์ ์ ์
// ๋ช
๋ น์ด ์ฒ๋ฆฌ ํจ์์ ์๊ทธ๋์ฒ ์ ์
typedef int (*CMD_FUNC_T)(int argc, char **argv);
// ๋ช
๋ น์ด์ ํด๋น ๋ช
๋ น์ด๋ฅผ ์ฒ๋ฆฌํ ํจ์ ์ ๋ณด๋ฅผ ์ ์ฅํ๋ ๊ตฌ์กฐ์ฒด ์ ์
typedef struct {
char *cmd; // ๋ช
๋ น์ด ๋ฌธ์์ด
uint8_t no; // ๋ช
๋ น์ด ๋ฒํธ (๊ณ ์ ์๋ณ์)
CMD_FUNC_T cbf; // ๋ช
๋ น์ด๋ฅผ ์ฒ๋ฆฌํ ํจ์ ํฌ์ธํฐ
char *remark; // ๋ช
๋ น์ด์ ๋ํ ์ค๋ช
๋ฌธ์์ด
} CMD_LIST_T;
// ๊ฐ ๋ช
๋ น์ด์ ๋ํ ์ฒ๋ฆฌ ํจ์ ์ ์ธ
static int cli_help(int argc, char *argv[]);
static int cli_echo(int argc, char *argv[]);
static int cli_led(int argc, char *argv[]);
static int cli_pwm(int argc, char *argv[]);
// ๋ช
๋ น์ด์ ํจ์ ์ ๋ณด๋ฅผ ์ ์ฅํ๋ ๋ฐฐ์ด ์ ์ธ ๋ฐ ์ด๊ธฐํ
const CMD_LIST_T gCmdListObj[] = {
{ "help", 1, cli_help, "help" },
{ "echo", 2, cli_echo, "echo [echo data]" },
{ "led", 3, cli_led, "led [2/3] [on/off]" },
{ "pwm", 4, cli_pwm, "pwm [0] [0~100]" },
{ NULL, 0, NULL, NULL }
};
// help ๋ช
๋ น์ด ์ฒ๋ฆฌ ํจ์
static int cli_help(int argc, char *argv[])
{
// ๋ฑ๋ก๋ ๋ชจ๋ ๋ช
๋ น์ด์ ๋ํ ์ค๋ช
๋ฌธ์์ด ์ถ๋ ฅ
for (int i = 0; gCmdListObj[i].cmd != NULL; i++) {
printf("%s\r\n", gCmdListObj[i].remark);
}
return 0;
}
// echo ๋ช
๋ น์ด ์ฒ๋ฆฌ ํจ์
static int cli_echo(int argc, char *argv[])
{
if (argc < 2) printf("Need more arguments\r\n");
printf("%s\r\n", argv[1]); // ์
๋ ฅ๋ ๋ฐ์ดํฐ ๊ทธ๋๋ก ์ถ๋ ฅ
return 0;
}
// led ๋ช
๋ น์ด ์ฒ๋ฆฌ ํจ์
static int cli_led(int argc, char *argv[])
{
if (argc < 3) printf("Need more arguments\r\n");
long no = strtol(argv[1], NULL, 10); // ๋ฌธ์ -> ์ซ์ ๋ณํ
int onoff = strcasecmp(argv[2], "off"); // off์ด๋ฉด 0์ ๋ฐํ
if (onoff != 0) onoff = 1; // 0์ด ์๋๋ฉด 1๋ก ๋ณํ
led_onoff((uint8_t)no, (uint8_t)onoff); // LED ์ ์ด ํจ์ ํธ์ถ
return 0;
}
// pwm ๋ช
๋ น์ด ์ฒ๋ฆฌ ํจ์
static int cli_pwm(int argc, char *argv[])
{
if (argc < 3) printf("Need more arguments\r\n");
// ๋ฌธ์ -> ์ซ์ ๋ณํ
long no = strtol(argv[1], NULL, 10);
long duty = strtol(argv[2], NULL, 10);
// duty ์ฃผ๊ธฐ ๊ฐ์ด ์ ํจ ๋ฒ์๋ฅผ ๋ฒ์ด๋ ๊ฒฝ์ฐ ์กฐ์
if (duty > 100) duty = 100;
if (duty < 0) duty = 0;
pwm_dimming((uint8_t)no, (uint8_t)duty); // PWM ์ ์ด ํจ์ ํธ์ถ
return 0;
}
// ๋ช
๋ น์ด ๋ฌธ์์ด ๋ถ์, ํด๋น ๋ช
๋ น์ด์ ์ฒ๋ฆฌ ํจ์ ํธ์ถ์ ์ํ ํจ์
bool cli_parser(uint8_t *buf)
{
#if 1
int argc = 0; // ๋ช
๋ น์ด์ ๊ฐฏ์
char *argv[10]; // ๋ช
๋ น์ด๋ฅผ ์ ์ฅํ ๋ฐฐ์ด
char *ptr; // ๋ฌธ์์ด ๋ถ๋ฆฌ๋ฅผ ์ํ ํฌ์ธํฐ ๋ณ์
// ์
๋ ฅ๋ ๋ฌธ์์ด์ ๊ณต๋ฐฑ ๋ฐ ๊ตฌ๋ถ์๋ก ๋ถ๋ฆฌํ์ฌ argv ๋ฐฐ์ด์ ์ ์ฅ
ptr = strtok((char *)buf, D_DELIMITER);
if (ptr == NULL) return false;
while(ptr != NULL) {
argv[argc] = ptr;
argc++;
ptr = strtok(NULL, D_DELIMITER);
}
// ์
๋ ฅ๋ ๋ช
๋ น์ด์ ๋ฑ๋ก๋ ๋ช
๋ น์ด๋ฅผ ๋น๊ตํ์ฌ ํด๋น ๋ช
๋ น์ด์ ์ฒ๋ฆฌ ํจ์ ํธ์ถ
for (int i=0; gCmdListObj[i].cmd != NULL; i++) {
if (strcasecmp(gCmdListObj[i].cmd, argv[0]) == 0) {
printf("Calling %s function with argc=%d\n", gCmdListObj[i].cmd, argc);
gCmdListObj[i].cbf(argc, argv); // ํด๋น ๋ช
๋ น์ด์ ์ฒ๋ฆฌ ํจ์ ํธ์ถ
return true;
}}
printf("Unsupported command..\r\n");
#else
char *ptr = strtok(buf, " "); //์ฒซ๋ฒ์งธ strtok ์ฌ์ฉ.
while (ptr != NULL) //ptr์ด NULL์ผ๋๊น์ง (strtok ํจ์๊ฐ NULL์ ๋ฐํํ ๋๊น์ง)
{
printf("%s\n", ptr); //์๋ฅธ ๋ฌธ์ ์ถ๋ ฅ
ptr = strtok(NULL, " "); //์๋ฅธ ๋ฌธ์ ๋ค์๋ถํฐ ๊ตฌ๋ถ์ ๋ ์ฐพ๊ธฐ
}
uart_regcbf(cli_parser); // UART ์์ ์ฝ๋ฐฑ ํจ์ ๋ฑ๋ก
#endif
return true;
}
// CLI ์ด๊ธฐํ ํจ์ (UART ์์ ์ฝ๋ฐฑ ํจ์ ๋ฑ๋ก)
void cli_init(void)
{
uart_regcbf(cli_parser);
}
์ํํ ๋์ led.c, pwm.c ํ์ผ ์์ฑ
4.1 led.c
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include "main.h"
#include "led.h"
void led_init(void)
{
printf("LED initialized...\r\n"); // LED ์ด๊ธฐํ ๋ฉ์์ง ์ถ๋ ฅ
}
//led on/off ํจ์
bool led_onoff(uint8_t no, uint8_t onoff)
{
GPIO_PinState sts = onoff ? GPIO_PIN_SET : GPIO_PIN_RESET;
switch (no) { // ์ ๋ฌ๋ ๊ฐ์ ๋ฐ๋ผ LED ์ํ ์ค์
case 2 :
HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, sts);
break;
case 3 :
HAL_GPIO_WritePin(LD3_GPIO_Port, LD3_Pin, sts);
break;
default :
return false;
}
return true; // ์ฒ๋ฆฌ ๊ฒฐ๊ณผ ๋ฐํ (์ฑ๊ณต: true, ์คํจ: false)
}
4.2 pwm.c
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <stdint.h>
#include "main.h"
extern TIM_HandleTypeDef htim3; // ํ์ด๋จธ ํธ๋ค๋ฌ ๋ณ์ ์ ์ธ
void pwm_init(void)
{
printf("Timer3 PWM start\r\n");
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_3); // TIM3 ์ฑ๋3 PWM ์์
}
// PWM ์ ํธ๋ก ๋ฐ๊ธฐ ์กฐ์ ํ๋ ํจ์
bool pwm_dimming(uint8_t no, uint8_t duty)
{
bool res = true; // ๋ฐํ์ฉ ๊ฒฐ๊ณผ ๋ณ์ ์ ์ธ
uint16_t ccr = (uint16_t)duty * 10; // duty ์ฃผ๊ธฐ๋ฅผ ํ์ด๋จธ์ Compare/Capture ๋ ์ง์คํฐ ๊ฐ์ผ๋ก ๋ณํ
switch (no) {
case 0 :
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_3, ccr);
// TIM3์ ์ฑ๋ 3์ Compare/Capture ๋ ์ง์คํฐ์ ccr ๊ฐ์ ์ค์ ํ์ฌ ๋ฐ๊ธฐ ์กฐ์
break;
default :
res = false;
}
return res; // ์ฒ๋ฆฌ ๊ฒฐ๊ณผ ๋ฐํ (์ฑ๊ณต: true, ์คํจ: false)
}
๐ ๊ฒฐ๊ณผ ์ฌ์ง
1, help ๋ช ๋ น์ด
2. echo ๋ช
๋ น์ด
3. led on/off ๋ช ๋ น์ด
4. pwm duty ๋ณ๊ฒฝ ๋ช ๋ น์ด
'embedded' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[stm32] ADC & DMA ์ค์ต (0) | 2023.09.06 |
---|---|
[stm32] ADC & DMA ์ด๋ก ์ ๋ฆฌ (0) | 2023.09.06 |
[stm32] UART ์ด๋ก ์ ๋ฆฌ (0) | 2023.08.16 |
[stm32] Timer ์ค์ต (0) | 2023.08.16 |
[stm32] Timer ์ด๋ก ์ ๋ฆฌ (0) | 2023.08.16 |