참고 사이트 :
https://github.com/blalor/avr-softuart
위 사이트에 나와있는 소스코드를 STM32F103에서 동작하도록 변경
9600bps에 맞췄습니다만 본인이 사용하는 클럭 설정이나 다른 코어라면 코어의 처리 속도등을 고려해서 Timer의 발생 시간을 조절해주어야 합니다.
계산해보면 1/9600 = 0.00010416... 이므로 오차율 감안하고 104us정도 나오도록 오실로스코프로 계산하면서 맞춰주면 될 것 같습니다.
##include <stdarg.h>
#include <stdio.h>
#define SU_TRUE 1
#define SU_FALSE 0
// 1 Startbit, 8 Databits, 1 Stopbit = 10 Bits/Frame
#define TX_NUM_OF_BITS (10)
volatile static unsigned char flag_tx_busy;
volatile static unsigned char timer_tx_ctr;
volatile static unsigned char bits_left_in_tx;
volatile static unsigned short internal_tx_buffer; /* ! mt: was type uchar - this was wrong */
#define UARTTXPORT GPIOA
#define UARTTXPIN GPIO_Pin_9
#define set_tx_pin_high() GPIO_SetBits(UARTTXPORT, UARTTXPIN)
#define set_tx_pin_low() GPIO_ResetBits(UARTTXPORT, UARTTXPIN)
extern void TIM2_IRQHandler(void);
void TIM2_IRQHandler(void)
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)
{
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
Tim2_IRQ();
}
}
void Tim2_IRQ(void)
{
unsigned char tmp;
// Transmitter Section
if ( flag_tx_busy == SU_TRUE ) {
tmp = timer_tx_ctr;
if ( --tmp == 0 ) { // if ( --timer_tx_ctr <= 0 )
if ( internal_tx_buffer & 0x01 ) {
set_tx_pin_high();
}
else {
set_tx_pin_low();
}
internal_tx_buffer >>= 1;
tmp = 3; // timer_tx_ctr = 3;
if ( --bits_left_in_tx == 0 ) {
flag_tx_busy = SU_FALSE;
}
}
timer_tx_ctr = tmp;
}
}
void gpio_init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
/* Enable the GPIO_LED clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
set_tx_pin_high(); /* mt: set to high to avoid garbage on init */
/* Configure Led pin as output */
GPIO_InitStruct.GPIO_Pin = UARTTXPIN;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(UARTTXPORT, &GPIO_InitStruct);
flag_tx_busy = SU_FALSE;
}
void timer_init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
/* Time base configuration */
TIM_TimeBaseStructure.TIM_Period = 70 - 1; //
TIM_TimeBaseStructure.TIM_Prescaler = 35; // Timer/Count2 Clock = 36Mhz / (35 + 1) = 1Mhz = 1 usec
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // Ä«¿îÅ͸ðµåµ¿ÀÛ
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
/* TIM2 counter enable */
TIM_Cmd(TIM2, ENABLE);
/* TIM IT enable */
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
/* Enable the TIM2 gloabal Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void softuart_init( void )
{
gpio_init();
/* 9600bps Setting */
timer_init();
}
unsigned char softuart_transmit_busy( void )
{
return ( flag_tx_busy == SU_TRUE ) ? 1 : 0;
}
void softuart_putchar( const char ch )
{
while ( flag_tx_busy == SU_TRUE ) {
; // wait for transmitter ready
// add watchdog-reset here if needed;
}
// invoke_UART_transmit
timer_tx_ctr = 3;
bits_left_in_tx = TX_NUM_OF_BITS;
internal_tx_buffer = ( ch << 1 ) | 0x200;
flag_tx_busy = SU_TRUE;
}
void softuart_puts( const char *s )
{
while ( *s ) {
softuart_putchar( *s++ );
}
}
void softuart_puts_P(char *string)
{
while(*string != '\0') softuart_putchar(*(string++));
}
void softuart_print(const char *fmt,...)
{
char string[256];
va_list ap;
va_start(ap,fmt);
vsprintf(string,fmt,ap);
va_end(ap);
softuart_puts_P(string);
}
void main(void)
{
softuart_init();
softuart_print("\r\nSoftuart Demo-Application Start \r\n");
}
'초보의 아웅다웅 설계하기 > STM32' 카테고리의 다른 글
Base Timer 인터럽트 사용 안하고 설정하기 (1) | 2018.12.20 |
---|---|
STM32F Sleep Mode에서 Uart로 Wakeup하기 (0) | 2018.12.06 |
24LC1025 데이터 Read, Write (0) | 2018.10.16 |
OLED QG-2864KSWLG01 내부 펌프 초기 코드 (0) | 2018.09.01 |
Partial Erase Done (areas with no algorithms skipped!) 에러 발생 (0) | 2018.08.17 |