roboforum.ru

Технический форум по робототехнике.

программирование UART (на Си)

Re: программирование UART (на Си)

MiBBiM » 08 янв 2010, 23:35

sercontrol вроде ещё для первого минибота написана, соответственно там нет защиты от всех "фич" минибота второй и выше версий :)

Re: программирование UART (на Си)

EdGull » 08 янв 2010, 23:37

да, на первом миниботе не было внутренней шину на уарте, соответственно не было закорота по Rx и Tx

Re: программирование UART (на Си)

unnAm3d » 08 янв 2010, 23:42

я бы попробовал на basic если бы не был уверен что проблема в коде и была бы необходимость проверить работоспособность платы. Но сейчас я уверен что где-то у меня не то в коде..

Добавлено спустя 1 минуту 55 секунд:
хм... т.е. есть нюансы при инициализации уарта? при закороченных RX и TX? не подскажите какие? :oops:

Re: программирование UART (на Си)

MiBBiM » 08 янв 2010, 23:46

прошивка sercontrol на миниботе не умеет защищаться от собственного вывода => будут глюки, наличие которых не зависит от твоего pc-кода.
прежде чем писать программы, наверное стоит поставить нормальный терминал и отладить работу прошивки на нем, не?
при закороченных rx<->tx и пк, и минибот слышат и видят все, что пишут в уарт.

Re: программирование UART (на Си)

unnAm3d » 08 янв 2010, 23:52

наверное стоит поставить нормальный терминал и отладить работу прошивки на нем

нормальный терминал? это какой-такой?))
при закороченных rx<->tx и пк, и минибот слышат и видят все, что пишут в уарт

ну т.е. прошивка должна обрабатывать char через один на rx ? или что... чего то я запутался(((( :cry:

Re: программирование UART (на Си)

MiBBiM » 09 янв 2010, 00:07

абсолютно любой :D
прошивка должна отключать прием во время передачи.

Re: программирование UART (на Си)

unnAm3d » 09 янв 2010, 02:10

хм.. а на какое время отключать прием? по delay или
while(!(UCSRA&(1<<TXC))) ;
? по второму варианту он видимо вообще из цикла не выходит.... а по первому - как вычислить время одного бод?

Re: программирование UART (на Си)

Vooon » 09 янв 2010, 03:14

Нет, нужно править usart_putchar() чтоб в начале отрубал Rx а потом обратно.
Но лучше весь вывод (на сколько помню stdin/stdout/stderr перенаправляется на usart_fdev) обернуть макросами
выключить и включить Rx.

Что-то вроде
Код: Выделить всёРазвернуть
#define DISABLE_RX() UCSRB &= ~(1<<RXEN)
#define ENABLE_RX()  UCSRB |= (1<<RXEN)


/* Сеанс черной магии.
* Подробности смотри <util/atomic.h>
*/
static __inline__ uint8_t __disblRxRet()
{
  DISABLE_RX();
  return 1;
}
static __inline__ void __enblRxParam(const uint8_t *__s)
{
  ENABLE_RX();
  (void)__s; // чтобы компилятор не сыпал предупреждений про неиспользуемую переменную
}

/* OUT_BLOCK_FORCEON() {
*   puts("output");
* }
*/
#define OUT_BLOCK_FORCEON() for(uint8_t __st __attribute__((__cleanup__(__enblRxParam))) = __disblRxRet(); __st; __st=0)


Добавлено спустя 24 минуты 11 секунд:
Но вообще сам sercontrol для минибота 2 не подходит.
Нужно перерабатывать протокол, теперь простым текстом не отделаешься, нужно подобие LIN (как минимум нужен контроль доступа к среде передачи, арбитраж, и прочие прелести «больших систем»).
Ну и проект фактически загнулся. А опыт полученный на этом порте я использовал при написании [[орфы]].

Re: программирование UART (на Си)

unnAm3d » 09 янв 2010, 12:58

To Vooon
Добрый день!
не подскажете, с какими оговорками можно собирать проект под минибот 2? хотя бы основные, на что нужно обратить внимание.

Re: программирование UART (на Си)

Vooon » 09 янв 2010, 23:53

Нужно проверить описание выводов (board.h), добавить выше приведенные макросы, заключить весь вывод в OUT_BLOCK_FORCEON(){}. Тогда если на шине будет только два устройства (мега и мост) то, думаю, будет работать.

Re: программирование UART (на Си)

unnAm3d » 10 янв 2010, 02:36

товарищи, выручайте!
уже третий день бьюсь с uart - все никак не выводит(((

что я тут мог неверно проинициализировать?(
Файл "irs_uart.h":
Код: Выделить всёРазвернуть
#ifndef USART_H_
#define USART_H_

#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <avr/io.h>
#include "global.h"

/**
* Use the following macros to determine the 'baud' parameter values
* for uart_init()
* @warning 'baud' SHOULD ALWAYS BE A CONSTANT or a lot of code
* will be generated.
*/
//#define USART_BAUD(baud) ((uint16_t)((F_CPU / (16.0 * (baud))) + 0.5) - 1)
#define USART_BAUD(baud) ((uint16_t)((F_CPU + (baud * 8L)) / (16L * (baud))) - 1) //! vg

/**
* Some typical baud rates
* Confirm the cpu clock rate will support the desired baud rate
*/
#define B115200 (USART_BAUD(115200L))
#define B76800  (USART_BAUD(76800UL))
#define B57600  (USART_BAUD(57600UL))
#define B38400  (USART_BAUD(38400UL))
#define B28800  (USART_BAUD(28800U))
#define B19200  (USART_BAUD(19200U))
#define B14400  (USART_BAUD(14400))
#define B9600   (USART_BAUD(9600))
#define B4800   (USART_BAUD(4800))
#define B2400   (USART_BAUD(2400))

/**
* Double Speed operation
* use the following macros to determine the 'baud' parameter values
* for uartInit() for Double Speed operation.  The macros above will
* also work just fine.
* @warning 'baud' SHOULD ALWAYS BE A CONSTANT or a lot of code
* will be generated.
*/
#define DOUBLE_SPEED_BIT (1<<15)
#define USART_2x_BAUD(baud) \
   (((uint16_t)((F_CPU / (8.0 * (baud))) + 0.5) - 1) | DOUBLE_SPEED_BIT)

/**
* Some typical baud rates
* Confirm the cpu clock rate will support the desired baud rate
*/
#define B2x115200 (USART_2x_BAUD(115200L))
#define B2x76800  (USART_2x_BAUD(76800UL))
#define B2x57600  (USART_2x_BAUD(57600UL))
#define B2x38400  (USART_2x_BAUD(38400UL))
#define B2x28800  (USART_2x_BAUD(28800U))
#define B2x19200  (USART_2x_BAUD(19200U))
#define B2x14400  (USART_2x_BAUD(14400))
#define B2x9600   (USART_2x_BAUD(9600))
#define B2x4800   (USART_2x_BAUD(4800))
#define B2x2400   (USART_2x_BAUD(2400))

//! Type of interrupt handler to use for uart interrupts.
/// Value may be SIGNAL or INTERRUPT.
/// \warning Do not change unless you know what you're doing.
#ifndef UART_INTERRUPT_HANDLER
#define UART_INTERRUPT_HANDLER   SIGNAL
#endif

// compatibility with most newer processors
#ifdef UCSRB
   #define UCR               UCSRB
#endif
// compatibility with old Mega processors
#if defined(UBRR) && !defined(UBRRL)
   #define   UBRRL            UBRR
#endif

/** defines
**/
#define UART_DISABLE_RX() UCSRB &= ~(1<<RXEN)
#define UART_ENABLE_RX()  UCSRB |= (1<<RXEN)

// USART file device
extern FILE usart_fdev;

/**
* This function initializes the USART
*
* @param baud baudrate divisor
* @return void
*
* Example
* @code
* usart_init(B9600);
* // or
* usart_init(USART_BAUD(9600));
* @endcode
*/
void usart_init(uint16_t baud);

/**
* Send one character to the UART.
*/
int usart_putchar(char c, FILE *stream);
int usart_putchar0(char c, FILE *stream);

/**
* Receive one character from the UART.
*/
int usart_getchar(FILE *stream);
int usart_getchar0(FILE *stream);

#endif /*USART_H_*/



Файл "irs_uart.с":
Код: Выделить всёРазвернуть
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <avr/io.h>
#include <avr/interrupt.h>

#include "irs_uart.h"

// usart file device
FILE usart_fdev = FDEV_SETUP_STREAM(usart_putchar, usart_getchar, _FDEV_SETUP_RW);

// This function initializes the USART
void usart_init(uint16_t baud) {
    // disable the USART
    UCSRB = 0x00;
    UCSRA = 0x00;

    if ( baud & DOUBLE_SPEED_BIT )
        UCSRA |= (1 << U2X);

    // Communication Parameters: 8 Data, 1 Stop, No Parity
    // USART Mode: Asynchronous
    UCSRC=0x86;
    UCSRB &= ~(UCSZ2);

    // load the baudrate divisor register
    UBRRL = baud;
    // output the upper four bits of the baudrate divisor
    UBRRH = (baud >> 8) & 0x0F;

    // enable the USART0 transmitter & receiver
    // enable RxD/TxD and interrupts
    UCSRB |= (1<<TXCIE)|(1<<RXCIE)|(1<<TXEN)|(1<<RXEN);
}

/*
* Send character c down the UART Tx, wait until tx holding register
* is empty.
*/
int usart_putchar(char c, FILE *stream) {
    if ( c == '\n' )
        usart_putchar('\r', stream);
    loop_until_bit_is_set(UCSRA, UDRE);
    UART_DISABLE_RX();
    UDR = c;
    return 0;
}

int usart_putchar0(char c, FILE *stream) {
    loop_until_bit_is_set(UCSRA, UDRE);
    UART_DISABLE_RX();
    UDR = c;
    return 0;
}

int usart_getchar(FILE *stream) {
    uint8_t c;
    loop_until_bit_is_set(UCSRA, RXC);
    c = UDR;
    if ( c == '\r' )
        c = '\n';
    return c;
}

int usart_getchar0(FILE *stream) {
    uint8_t c;
    loop_until_bit_is_set(UCSRA, RXC);
    c = UDR;
    return c;
}

UART_INTERRUPT_HANDLER(SIG_UART_RECV) {

}

// UART Transmit Complete Interrupt Handler
UART_INTERRUPT_HANDLER(SIG_UART_TRANS) {
    UART_ENABLE_RX();
}


буду очень благодарен за любые подсказки.

Re: программирование UART (на Си)

Vooon » 10 янв 2010, 03:15

Толку использовать прерывания, если вызовы все равно блокирующие?
Не стоит использовать константу при инициализации конфигурационных битов регистра.
Лучше воспользоваться записью (1<<REGISTER_BIT_NAME1)|(1<<REGISTER_BIT_NAME2)...
Так мне не придется каждый раз смотреть документацию, проверять а те-ли биты установлены?
Т.е. читаемость будет лучше.

И еще маленькое замечание, копируете код — оставляйте заголовок с копирайтом/лицензией.

Добавлено спустя 5 минут 8 секунд:
Сегодня не буду бить тапком за портянки в посте.
Цепляй файл к посту, а в него добавляй только наиболее важные куски.
Автодетект подсветки кода сломан, пиши язык принудительно:
Код: Выделить всёРазвернуть
[code=cpp][/code]


Re: программирование UART (на Си)

unnAm3d » 10 янв 2010, 14:31

Добрый день))
Толку использовать прерывания, если вызовы все равно блокирующие?

объясните, пожалуйста, не совсем понял что блокирует вызов обработчика прерывания....
И еще маленькое замечание, копируете код — оставляйте заголовок с копирайтом/лицензией.

ну это моя болезнь вырезать все комменты авторства((( те комменты что Вы видели в примере кода (информативные) будут вырезаны тоже.
А насчет читаемости - изменил и выложу ниже:
irs_uart.h
Код: Выделить всёРазвернуть
// ........
#define USART_BAUD(baud) ((uint16_t)((F_CPU + (baud * 8L)) / (16L * (baud))) - 1)
#define B9600   (USART_BAUD(9600))
#ifndef UART_INTERRUPT_HANDLER
#define UART_INTERRUPT_HANDLER   SIGNAL
#endif
#define UART_DISABLE_RX() UCSRB &= ~(1<<RXEN)
#define UART_ENABLE_RX()  UCSRB |= (1<<RXEN)
// .........

irs_uart.c
Код: Выделить всёРазвернуть
// ........
// This function initializes the USART
void usart_init(uint16_t baud) {
    // disable the USART
    UCSRB = 0x00;
    UCSRA = 0x00;

    if ( baud & DOUBLE_SPEED_BIT )
        UCSRA |= (1 << U2X);

    // Communication Parameters: 8 Data, 1 Stop, No Parity
    // USART Mode: Asynchronous
    UCSRC |= (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);
    UCSRC &= (~(1<<UMSEL))&(~(1<<UPM1))&(~(1<<UPM0))&(~(1<<USBS))&(~(1<<UCPOL));
    UCSRB &= ~(UCSZ2);

    // load the baudrate divisor register
    UBRRL = baud;
    // output the upper four bits of the baudrate divisor
    UBRRH = (baud >> 8) & 0x0F;

    // enable the USART0 transmitter & receiver
    // enable RxD/TxD and interrupts
    UCSRB |= (1<<TXCIE)|(1<<RXCIE)|(1<<TXEN)|(1<<RXEN);
}
// .......
int usart_putchar(char c, FILE *stream) {
    if ( c == '\n' )
        usart_putchar('\r', stream);
    loop_until_bit_is_set(UCSRA, UDRE);
    UART_DISABLE_RX();
    UDR = c;
    return 0;
}

int usart_putchar0(char c, FILE *stream) {
    loop_until_bit_is_set(UCSRA, UDRE);
    UART_DISABLE_RX();
    UDR = c;
    return 0;
}
// .......
UART_INTERRUPT_HANDLER(SIG_UART_RECV) {

}

// UART Transmit Complete Interrupt Handler
UART_INTERRUPT_HANDLER(SIG_UART_TRANS) {
    UART_ENABLE_RX();
}
// .......

main.c
Код: Выделить всёРазвернуть
// .......
usart_init(B9600);
    // use USART device for stdio
    stderr = stdout = stdin = &usart_fdev;

    char tmpbuff[5] = {'H', 'E', 'L', 'L', 'O'};

    while(1) {
        for(unsigned int i=0; i<5; i++)
            usart_putchar(tmpbuff[i], stdout);
    }
// .......


// ..... - означают опущенные куски кода.
в терминал код ничего не выводит(((

PS примите извинения за неверное оформление предыдущего поста...

Re: программирование UART (на Си)

Vooon » 10 янв 2010, 17:25

Это я бы написал проще:
UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0)|(0<<UCPOL)|(0<<UMSEL)|(0<<UPM1)|(0<<UPM0)|(0<<USBS);
(нули можно опустить)

Код: Выделить всёРазвернуть
int usart_putchar(char c, FILE *stream) {
    if ( c == '\n' )
        usart_putchar('\r', stream);
    loop_until_bit_is_set(UCSRA, UDRE); // перестраховка
    UART_DISABLE_RX();
    UDR = c;
    loop_until_bit_is_set(UCSRA, UDRE); // ждем пока символ отравляется
    UART_ENABLE_RX(); // отправили, включили прием
    return 0;
}

//...
    usart_init(B9600);
    // use USART device for stdio
    stderr = stdout = stdin = &usart_fdev;

    char tmpbuff[] = "Hello world!\n";

    while(1) {
        puts(tmpbuf);
    }
//...


Блокирующее значит, что пока байт не будет отправлен ф-ция будет ждать.
Прерывания в таком режиме только усложняют отладку. Если бы был буферизированный вывод, то тогда это имеет смысл.
А прерывания ты не забыл разрешить?

Re: программирование UART (на Си)

unnAm3d » 10 янв 2010, 20:51

спасибо!
работает. использовал Ваш пример подобия atomic.
только вот... шлю например:
Код: Выделить всёРазвернуть
char tmpbuff[] = "Hi!"

а в терминал (использовал и hyperterminal и com port toolkit) приходит:
00 3E 60 CC 80
это по-моему совсем не то.. ни в ANSI, ни в ASCI..
с чем это связано?


Rambler\'s Top100 Mail.ru counter