초보의 아웅다웅 설계하기/STM32

SoftUart Only TX

로망와니 2018. 10. 22. 13:07

참고 사이트 : 

https://github.com/blalor/avr-softuart


위 사이트에 나와있는 소스코드를 STM32F103에서 동작하도록 변경

9600bps에 맞췄습니다만 본인이 사용하는 클럭 설정이나 다른 코어라면 코어의 처리 속도등을 고려해서 Timer의 발생 시간을 조절해주어야 합니다. 

계산해보면 1/9600 = 0.00010416... 이므로 오차율 감안하고 104us정도 나오도록 오실로스코프로 계산하면서 맞춰주면 될 것 같습니다.

softuart.c



##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");

}