Код из статьи иногда пропускал ошибки на длинных посылках.
Здесь рабочий, немного подправленный код для STM32F103C8T6 для среды CooCox.
Для STM32F030F4P6 SOFT UART незаменимая штука! Там всего 1 UART.
Тест «BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAB» — LED ON на букву "А" в посылке.
Код
// SOFT UART - STM32F103C8T6 - CooCox (1.05.2015, zz555)
// http://we.easyelectronics.ru/STM32/vcp-soft_uart_x3-modifikaciya-stm32vldiscovery.html
// Для STM32F030F4P6 незаменимая штука! Там всего 1 UART.
// Тест «BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAB» — LED ON на букву "А" в посылке
// 10 bit protocol: 1-start bit, 8-bit data, 1-stop bit (bps = timer_irq/3)
//
// Recive bytes:
// 1 - waiting flag_rx_rdy = 1
// 2 - read rx_buf[]
// 3 - flag_rx_rdy = 0, rx_byte_no = 0
//
// Transmit bytes:
// 1 - copy bytes to tx_buf[]
// 2 - run tx_uart(number of bytes in tx_buf);
//
// PA1 (IN) RX
// PC13 (OUT) LED
#include "stm32f10x.h"
void tx_uart(uint8_t bytes);
#define RX (GPIOA->IDR & GPIO_IDR_IDR1)==GPIO_IDR_IDR1 // PA1 IN RX
#define TX0 GPIOA->BSRR = GPIO_BSRR_BR0 // PA0 OUT TX OFF
#define TX1 GPIOA->BSRR = GPIO_BSRR_BS0 // PA0 OUT TX ON
#define PC13_0 GPIOC->BRR |= GPIO_ODR_ODR13 // PC13 OUT LED OFF
#define PC13_1 GPIOC->BSRR |= GPIO_ODR_ODR13 // PC13 OUT LED ON
#define PC13_N GPIOC->ODR^=GPIO_ODR_ODR13 // PC13 OUT LED INVERT
#define BUF_SIZE 256
uint8_t rx_buf[BUF_SIZE];
uint8_t tx_buf[BUF_SIZE];
uint8_t rx_byte;
uint8_t tx_byte;
uint8_t rx_byte_no;
uint8_t state_rx;
uint8_t state_tx;
uint8_t rx_counter;
uint8_t tx_counter;
uint8_t rx_counter_equ;
uint8_t rx_mask;
uint8_t tx_mask;
uint8_t bit_no_rx;
uint8_t bit_no_tx;
uint8_t flag_rx_rdy;
uint8_t flag_tx_rdy;
uint8_t err;
uint8_t i;
uint8_t k;
uint32_t TimingDelay;
void TIM2_IRQHandler(void) {
// RX
if (rx_byte_no>0) {
k++;
if (k>30) {k=0; flag_rx_rdy=1;}
}
if (flag_rx_rdy==0) {
if (state_rx>1) {k=0; rx_counter++;} else rx_counter=1;
if (rx_counter==rx_counter_equ) {
rx_counter=0;
switch (state_rx) {
case 1: // start bit
{
if (RX) {} else { // PA1 - RX
rx_byte=0; bit_no_rx=1; state_rx=2; rx_counter_equ=4;
}
break;
}
case 2: // data bits
{
if (RX) rx_mask=1; else rx_mask=0; // PA1 - RX
rx_byte >>= 1;
rx_mask <<= 7;
rx_byte |= rx_mask;
bit_no_rx++;
if (bit_no_rx==9) state_rx=3;
rx_counter_equ=3;
break;
}
case 3: // stop bit
{
if (RX) { // PA1 - RX
rx_buf[rx_byte_no]=rx_byte;
rx_byte_no++;
if (rx_byte_no==BUF_SIZE-1) rx_byte_no=0;
} else err=1;
state_rx=1;
rx_counter_equ=1;
break;
}
}
}
}
if (flag_tx_rdy==1) { // TX
tx_counter++;
if (tx_counter==3) {
tx_counter=0;
switch (state_tx) {
case 1: // start bit
{
TX0;
bit_no_tx=1;
state_tx=2;
break;
}
case 2: // data bits
{
tx_mask=tx_byte & 1;
tx_byte >>= 1;
if (tx_mask==0) TX0; else TX1;
bit_no_tx++;
if (bit_no_tx>8) state_tx=3;
break;
}
case 3: // stop bit
{
TX1;
flag_tx_rdy=0;
break;
}
}
}
}
TIM2->SR &= ~TIM_SR_UIF;
}
// Функция временной задержки в милисекундах
void Delay_ms(uint32_t nTime) {
TimingDelay = nTime*2400;
while (TimingDelay != 0) TimingDelay--;
}
void flash (void) {
err=0;
for(i=0; i<10; i++) {
PC13_0;
Delay_ms(10);
PC13_1;
Delay_ms(10);
}
}
void tx_uart(uint8_t bytes) {
uint8_t i;
tx_counter=0;
for (i=0; i<bytes; i++) {
while (flag_tx_rdy==1) {}
tx_byte=tx_buf[i];
state_tx=1;
flag_tx_rdy=1;
}
}
//================================================================================
void Init_STM() {
RCC->APB2ENR |= (RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPCEN);
GPIOA->CRL &= ~(GPIO_CRL_MODE0 | GPIO_CRL_CNF0 | GPIO_CRL_MODE1 | GPIO_CRL_CNF1);
GPIOA->CRL |= (GPIO_CRL_MODE0_0 | GPIO_CRL_CNF1_1); // PA0 (OUT) TX, PA1 (IN) RX
GPIOA->BSRR = GPIO_BSRR_BS1;
GPIOC->CRH |= GPIO_CRH_MODE13; // PC13 (OUT) LED
// Инициализация таймера TIM2
RCC->CFGR |= RCC_CFGR_HPRE_DIV2; // sys_clk/2 (36/2=18 MHz)
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; // Разрешаем тактирование TIM2
TIM2->DIER |= TIM_DIER_UIE; // Update interrupt enable
TIM2->PSC = 625-1; // Предделитель частоты перед таймером (при 0 максимальная частота) (18000/625=28.8 KHz)
TIM2->ARR = 1; // До скольки считает таймер (28.8/3=9600 Hz)
TIM2->CR1 |= (TIM_CR1_CEN | TIM_CR1_ARPE); // Запускаем таймер
NVIC_EnableIRQ (TIM2_IRQn); // Разрешаем прерывания TIM2
}
//================================================================================
int main (void) {
Init_STM();
// Init_UART
state_rx=1;
rx_counter_equ=1;
rx_byte_no=0;
rx_byte_no=0;
flag_rx_rdy=0;
flag_tx_rdy=0;
TX1;
PC13_0;
Delay_ms(10); // Пауза 0,01 с
PC13_1;
while (1) {
if (flag_rx_rdy==1) {
if (err==1) flash();
for(i=0; i<rx_byte_no; i++) {
tx_buf[i]=rx_buf[i];
if (rx_buf[i]==65) PC13_0; // "A" - код 65
}
tx_uart(rx_byte_no);
Delay_ms(10);
PC13_1;
rx_byte_no=0;
flag_rx_rdy=0;
}
}
}
// http://we.easyelectronics.ru/STM32/vcp-soft_uart_x3-modifikaciya-stm32vldiscovery.html
// Для STM32F030F4P6 незаменимая штука! Там всего 1 UART.
// Тест «BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAB» — LED ON на букву "А" в посылке
// 10 bit protocol: 1-start bit, 8-bit data, 1-stop bit (bps = timer_irq/3)
//
// Recive bytes:
// 1 - waiting flag_rx_rdy = 1
// 2 - read rx_buf[]
// 3 - flag_rx_rdy = 0, rx_byte_no = 0
//
// Transmit bytes:
// 1 - copy bytes to tx_buf[]
// 2 - run tx_uart(number of bytes in tx_buf);
//
// PA1 (IN) RX
// PC13 (OUT) LED
#include "stm32f10x.h"
void tx_uart(uint8_t bytes);
#define RX (GPIOA->IDR & GPIO_IDR_IDR1)==GPIO_IDR_IDR1 // PA1 IN RX
#define TX0 GPIOA->BSRR = GPIO_BSRR_BR0 // PA0 OUT TX OFF
#define TX1 GPIOA->BSRR = GPIO_BSRR_BS0 // PA0 OUT TX ON
#define PC13_0 GPIOC->BRR |= GPIO_ODR_ODR13 // PC13 OUT LED OFF
#define PC13_1 GPIOC->BSRR |= GPIO_ODR_ODR13 // PC13 OUT LED ON
#define PC13_N GPIOC->ODR^=GPIO_ODR_ODR13 // PC13 OUT LED INVERT
#define BUF_SIZE 256
uint8_t rx_buf[BUF_SIZE];
uint8_t tx_buf[BUF_SIZE];
uint8_t rx_byte;
uint8_t tx_byte;
uint8_t rx_byte_no;
uint8_t state_rx;
uint8_t state_tx;
uint8_t rx_counter;
uint8_t tx_counter;
uint8_t rx_counter_equ;
uint8_t rx_mask;
uint8_t tx_mask;
uint8_t bit_no_rx;
uint8_t bit_no_tx;
uint8_t flag_rx_rdy;
uint8_t flag_tx_rdy;
uint8_t err;
uint8_t i;
uint8_t k;
uint32_t TimingDelay;
void TIM2_IRQHandler(void) {
// RX
if (rx_byte_no>0) {
k++;
if (k>30) {k=0; flag_rx_rdy=1;}
}
if (flag_rx_rdy==0) {
if (state_rx>1) {k=0; rx_counter++;} else rx_counter=1;
if (rx_counter==rx_counter_equ) {
rx_counter=0;
switch (state_rx) {
case 1: // start bit
{
if (RX) {} else { // PA1 - RX
rx_byte=0; bit_no_rx=1; state_rx=2; rx_counter_equ=4;
}
break;
}
case 2: // data bits
{
if (RX) rx_mask=1; else rx_mask=0; // PA1 - RX
rx_byte >>= 1;
rx_mask <<= 7;
rx_byte |= rx_mask;
bit_no_rx++;
if (bit_no_rx==9) state_rx=3;
rx_counter_equ=3;
break;
}
case 3: // stop bit
{
if (RX) { // PA1 - RX
rx_buf[rx_byte_no]=rx_byte;
rx_byte_no++;
if (rx_byte_no==BUF_SIZE-1) rx_byte_no=0;
} else err=1;
state_rx=1;
rx_counter_equ=1;
break;
}
}
}
}
if (flag_tx_rdy==1) { // TX
tx_counter++;
if (tx_counter==3) {
tx_counter=0;
switch (state_tx) {
case 1: // start bit
{
TX0;
bit_no_tx=1;
state_tx=2;
break;
}
case 2: // data bits
{
tx_mask=tx_byte & 1;
tx_byte >>= 1;
if (tx_mask==0) TX0; else TX1;
bit_no_tx++;
if (bit_no_tx>8) state_tx=3;
break;
}
case 3: // stop bit
{
TX1;
flag_tx_rdy=0;
break;
}
}
}
}
TIM2->SR &= ~TIM_SR_UIF;
}
// Функция временной задержки в милисекундах
void Delay_ms(uint32_t nTime) {
TimingDelay = nTime*2400;
while (TimingDelay != 0) TimingDelay--;
}
void flash (void) {
err=0;
for(i=0; i<10; i++) {
PC13_0;
Delay_ms(10);
PC13_1;
Delay_ms(10);
}
}
void tx_uart(uint8_t bytes) {
uint8_t i;
tx_counter=0;
for (i=0; i<bytes; i++) {
while (flag_tx_rdy==1) {}
tx_byte=tx_buf[i];
state_tx=1;
flag_tx_rdy=1;
}
}
//================================================================================
void Init_STM() {
RCC->APB2ENR |= (RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPCEN);
GPIOA->CRL &= ~(GPIO_CRL_MODE0 | GPIO_CRL_CNF0 | GPIO_CRL_MODE1 | GPIO_CRL_CNF1);
GPIOA->CRL |= (GPIO_CRL_MODE0_0 | GPIO_CRL_CNF1_1); // PA0 (OUT) TX, PA1 (IN) RX
GPIOA->BSRR = GPIO_BSRR_BS1;
GPIOC->CRH |= GPIO_CRH_MODE13; // PC13 (OUT) LED
// Инициализация таймера TIM2
RCC->CFGR |= RCC_CFGR_HPRE_DIV2; // sys_clk/2 (36/2=18 MHz)
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; // Разрешаем тактирование TIM2
TIM2->DIER |= TIM_DIER_UIE; // Update interrupt enable
TIM2->PSC = 625-1; // Предделитель частоты перед таймером (при 0 максимальная частота) (18000/625=28.8 KHz)
TIM2->ARR = 1; // До скольки считает таймер (28.8/3=9600 Hz)
TIM2->CR1 |= (TIM_CR1_CEN | TIM_CR1_ARPE); // Запускаем таймер
NVIC_EnableIRQ (TIM2_IRQn); // Разрешаем прерывания TIM2
}
//================================================================================
int main (void) {
Init_STM();
// Init_UART
state_rx=1;
rx_counter_equ=1;
rx_byte_no=0;
rx_byte_no=0;
flag_rx_rdy=0;
flag_tx_rdy=0;
TX1;
PC13_0;
Delay_ms(10); // Пауза 0,01 с
PC13_1;
while (1) {
if (flag_rx_rdy==1) {
if (err==1) flash();
for(i=0; i<rx_byte_no; i++) {
tx_buf[i]=rx_buf[i];
if (rx_buf[i]==65) PC13_0; // "A" - код 65
}
tx_uart(rx_byte_no);
Delay_ms(10);
PC13_1;
rx_byte_no=0;
flag_rx_rdy=0;
}
}
}