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

Обсуждаем контроллеры компании Atmel.
Ответить
Грызет канифоль
Сообщения: 286
Зарегистрирован: Сб фев 06, 2010 20:39:59

Сообщение LEVV2006 »

Всем привет!

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

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

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

А если например на МК есть 2 аппаратным UART. Как быть в таком случае?
Реклама
Опытный кот
Аватара пользователя
Сообщения: 760
Зарегистрирован: Сб окт 22, 2016 17:33:32
Откуда: кг

Сообщение Карбофос »

Изучите stdiodemo из исходников avr-libc.
А вообще, конечно-же, много разных вариантов.
Реклама
Грызет канифоль
Сообщения: 286
Зарегистрирован: Сб фев 06, 2010 20:39:59

Сообщение LEVV2006 »

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

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

По умолчанию библиотека 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 (Пока не могу добиться стабильной работы).
Опытный кот
Аватара пользователя
Сообщения: 760
Зарегистрирован: Сб окт 22, 2016 17:33:32
Откуда: кг

Сообщение Карбофос »

Вот только в 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 раза.
Реклама
Эиком - электронные компоненты и радиодетали
Грызет канифоль
Сообщения: 286
Зарегистрирован: Сб фев 06, 2010 20:39:59

Сообщение LEVV2006 »

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

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_ */
Реклама
Опытный кот
Аватара пользователя
Сообщения: 760
Зарегистрирован: Сб окт 22, 2016 17:33:32
Откуда: кг

Сообщение Карбофос »

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

Вернуться в «AVR»