Обсуждаем контроллеры компании Atmel.
Ответить

Потоки в библиотеке stdio.h

Сб окт 30, 2021 12:07:36

Всем привет!

Для ввода и вывода данных по UART я использую библиотеку stdio.h и ей потоки.

Но тут мне потребовалось в дополнений реализовать программный UART интерфейс.

И возник такой вопрос. Как воспользоваться библиотекой stdio.h если её 2 стандартных потока (stdin и stdout) уже заняты аппаратным UART?

А если например на МК есть 2 аппаратным UART. Как быть в таком случае?

Re: Потоки в библиотеке stdio.h

Сб окт 30, 2021 15:00:53

Изучите stdiodemo из исходников avr-libc.
А вообще, конечно-же, много разных вариантов.

Re: Потоки в библиотеке stdio.h

Сб окт 30, 2021 20:04:05

Ну..... кое что у меня заработало.

Суть проблемы.

По умолчанию библиотека stdio.h заточена под 3 потока. (stdin, stdout, stderr). И следовательно для двухстороннего общения по 2 UART этого мало.

Что сделал чтобы заработало.

Файл stdio.h запрещен к изменению так как является частью среды разработки. Я сохранил копию файла stdio.h и добавил в свой проект под новым именем stdio_dual.h. Во всем проекте заменил stdio.h на stdio_dual.h. И внес в файл следующие изменения:

Добавил 2 строчки

Код:
//Было
#define stdin (__iob[0])
#define stdout (__iob[1])
#define stderr (__iob[2])
//Добавил
#define stdinsoft (__iob[3])
#define stdoutsoft (__iob[4])

Теперь спокойно можно организовать прием и передачу по 2 интерфейсам

Код:
static FILE uart = FDEV_SETUP_STREAM(uart_putchar, uart_getchar, _FDEV_SETUP_RW);
static FILE Soft_uart = FDEV_SETUP_STREAM(Soft_uart_putchar, Soft_uart_getchar, _FDEV_SETUP_RW);

stdin=stdout=&uart;
stdinsoft=stdoutsoft=&Soft_uart;

Как читать и писать в порт

Код:
fscanf(stdin,"%s",&StringUART);
fprintf(stdout,"USART = %s\n",StringUART);

fscanf(stdinsoft,"%s",&StringUART);
fprintf(stdoutsoft,"Soft_USART = %s\n",StringUART);

Подводные камни:

Компилятор не мог найти эти переменные: stdinsoft и stdoutsoft. Мне пришлось их продублировать в main.h. Спустя некоторое время я решил их закомментировать и компилятор ругаться по новой не стал. При этом все продолжило работать.

PS/ К сожалению пока тест проводился только на одном аппаратном UART. И частично на программном UART (Пока не могу добиться стабильной работы).

Re: Потоки в библиотеке stdio.h

Сб окт 30, 2021 20:14:57

Вот только в iob.c определение:
Код:
#include <stdint.h>
#include <stdio.h>

#include "stdio_private.h"

FILE *__iob[3];         /* stdin, stdout, stderr */


Конечно-же, stdio.h править или подменять не следует.
Последний раз редактировалось Карбофос Сб окт 30, 2021 22:14:00, всего редактировалось 2 раз(а).

Re: Потоки в библиотеке stdio.h

Сб окт 30, 2021 22:12:27

Было найдено более оригинальное решение. Думаю стоит его выложить целиком. Может кому то и пригодится.
Ничего что я делал выше, делать не надо. Все на оригинальных файлах.

main.c
Код:
#include "main.h"
uint8_t StringUART[50]={'\0'};
int main(void)
{
   init_USART();
   fprintf(&mystd,"Test\n");
   while (1)
   {
      if (UARTRead)
      {
         fscanf(&mystd,"%s",&StringUART);
         fprintf(&mystd,"USART = %s\n",StringUART);
      }
   }
}

main.h
Код:
#ifndef MAIN_H_
#define MAIN_H_

#define F_CPU 16000000UL //частота МК

#include <avr/io.h>
#include <util/delay.h>
#include <stdio.h>
#include "UART.h"

extern FILE* mystd;
#endif

UART.c
Код:
#include "UART.h"

FILE mystd = FDEV_SETUP_STREAM(uart_putchar, uart_getchar, _FDEV_SETUP_RW);

void init_USART() //инициализация USART
{
   UBRR0L = UBRRL_value;
   UBRR0H = (UBRRL_value>>8);
   UCSR0B |=(1<<TXEN0)|(1<<RXEN0);
   UCSR0C |=(1<<UCSZ01)|(1<<UCSZ00)|(1<<USBS0);
}

 static int uart_putchar(char c, FILE *stream) //отправка данных по USART
{
   if (c == '\n')
   uart_putchar('\r', stream);
   while(!(UCSR0A&(1<<UDRE0)));
   UDR0=c;
   return 0;
}

 static int uart_getchar(FILE *stream) //чтение данных по USART
{
   while(!(UCSR0A&(1<<RXC0)));
   return UDR0;
}

UART.h
Код:
#ifndef UART_H_
#define UART_H_

#include <avr/io.h>
#include <stdio.h>
#define F_CPU 16000000UL //частота МК
#define BAUD 9600L
#define UBRRL_value (F_CPU/(BAUD*16))-1
#define UARTRead UCSR0A&(1<<RXC0)

//прототипы функций
void init_USART();
static int uart_putchar(char c, FILE *stream); //отправка данных по USART
static int uart_getchar(FILE *stream); //чтение данных по USART
#endif /* UART_H_ */

Re: Потоки в библиотеке stdio.h

Сб окт 30, 2021 22:27:37

Вот и чудесно.
Интереса ради, можете AVR303 appnote глянуть, там в примере кольцевые буферы приема/передачи организованы через прерывания.
Ответить