0 / 0 / 0
Регистрация: 01.05.2010
Сообщений: 619
|
|
1 | |
Буфер Uart на Си(решено)15.12.2011, 11:18. Показов 12260. Ответов 19
Метки нет (Все метки)
первый опыт ваяния чего либо на Си. до этого неплохо делал программки на асме и в принципе не знал горя пока не понял что надо расти. (да и количество готовых библиотек соблазняет)
для начала решил сделать буфер для UART и вот если переменные на асме выглядят так : Код
.equ MAXBUFF_IN = 10 ; Размер в байтах .equ MAXBUFF_OUT = 10 IN_buff: .byte MAXBUFF_IN ; Буфер приема IN_PTR_S: .byte 1 ; Указатель начала IN_PTR_E: .byte 1 ; Указатель конца IN_FULL: .byte 1 ; Флаг переполнения OUT_buff: .byte MAXBUFF_OUT ; Буфер передачи OUT_PTR_S: .byte 1 ; Указатель начала OUT_PTR_E: .byte 1 ; Указатель конца OUT_FULL: .byte 1 ; Флаг переполнения. Код
unsykned char MAXBUFF_IN[10]; // Буфер приема массив unsykned char IN_PTR_S; // Указатель начала unsykned char IN_PTR_E; // Указатель конца unsykned char IN_FULL; // Флаг переполнения unsykned char MAXBUFF_OUT[10]; // Буфер передачи массив unsykned char OUT_PTR_S; // Указатель начала unsykned char OUT_PTR_E; // Указатель конца unsykned char OUT_FULL; // Флаг переполнения. Код
RX_OK: PUSHF ; Макрос, пихающий в стек SREG и R16 PUSH R17 PUSH R18 PUSH XL PUSH XH LDI XL,low(IN_buff) ; Берем адрес начала буффера LDI XH,high(IN_buff) LDS R16,IN_PTR_E ; Берем смещение точки записи LDS R18,IN_PTR_S ; Берем смещение точки чтения ADD XL,R16 ; Сложением адреса со смещением CLR R17 ; получаем адрес точки записи ADC XH,R17 IN R17,UDR ; Забираем данные ST X,R17 ; сохраняем их в кольцо INC R16 ; Увеличиваем смещение CPI R16,MAXBUFF_IN ; Если достигли конца BRNE NoEnd CLR R16 ; переставляем на начало NoEnd: CP R16,R18 ; Дошли до непрочитанных данных? BRNE RX_OUT ; Если нет, то просто выходим RX_FULL: LDI R18,1 ; Если да, то буффер переполнен. STS IN_FULL,R18 ; Записываем флаг наполненности RX_OUT: STS IN_PTR_E,R16 ; Сохраняем смещение. Выходим POP XH POP XL POP R18 POP R17 POPF ; Достаем SREG и R16 RETI что можете посоветовать? кто знает хорошую книжку по Си (по СИ не СИ++) для микроконтроллеров в которой всё разжёвано (с примерами.)
0
|
15.12.2011, 11:18 | |
Ответы с готовыми решениями:
19
[решено] Помогите разобраться с UART [Решено] Неверный UART на ATmega328P [РЕШЕНО] Не работает UART на stm32l151 [ Решено ] A6 GSM модуль - проблема с UART |
MCSD: APP BUILDER
8794 / 1073 / 104
Регистрация: 17.06.2006
Сообщений: 12,602
|
|
15.12.2011, 11:35 | 2 |
хорошая, нехорошая не знаю, посмотри
Шпак Ю.А. Программирование на языке C для AVR и PIC микроконтроллеров http://myrknig.som/knigi/programming/11 ... lerov.html
0
|
0 / 0 / 0
Регистрация: 01.05.2010
Сообщений: 619
|
|
15.12.2011, 11:45 | 3 |
спасибо. поставил на скачивание
у меня вопрос к знатокам: у меня есть книга !C++ для чайников! и там есть пример работы с массивами(почти то что мне нужно) но меня гложут смутные сомнения что то что написано на с++ не прокатит на с, или это не так?
0
|
MCSD: APP BUILDER
8794 / 1073 / 104
Регистрация: 17.06.2006
Сообщений: 12,602
|
|
15.12.2011, 11:58 | 4 |
вот ещё глянь
Название: GCC. Полное руководство. Автор: Гриффитс Иртур http://myrknig.som/knigi/programming/11 ... dstvo.html
0
|
4 / 4 / 0
Регистрация: 12.03.2013
Сообщений: 24
|
|
15.12.2011, 15:13 | 5 |
Почему еще никто не советовал WinDjview Керниган Ритчи Язык программирования C.
Работа с массивами там очень хорошо описана. А про особенности на микроконтроллерах в статьях на сайте.
0
|
0 / 0 / 0
Регистрация: 14.07.2011
Сообщений: 96
|
|
15.12.2011, 17:07 | 6 |
В дополнение к Кернигану и Ритчи советую http://www.ozon.ru/context/detail/id/4369459/
Orsomum, напиши в псевдокоде, что ты хочешь сделать с буфером, вроде: Код
if(пришел байт) { поместить байт в буфер по индексу индекс_1; инкрементировать индекс_1; if(индекс_1 >= РАЗМЕР_БУФЕРА) { индекс_1 = 0; } инкрементировать количество_символов_в_буфере; }
0
|
0 / 0 / 0
Регистрация: 01.05.2010
Сообщений: 619
|
|
15.12.2011, 18:48 | 7 |
Сообщение от tuko
{ поместить байт в буфер по индексу индекс_1; инкрементировать индекс_1; if(индекс_1 >= РАЗМЕР_БУФЕРА) { индекс_1 = 0; } инкрементировать количество_символов_в_буфере; } По конкретному алгоритму подскажем. спасибо за ссылку. по поводу записи в буфер. псевдокод: Код
In[In_ptr_s]= UDR In_ptr_s++ if In_ptr_s = 10 then In_ptr_s = 0 else if In_ptr_s = In_ptr_e then exit else IN_FULL = In_ptr_e
0
|
0 / 0 / 0
Регистрация: 14.07.2011
Сообщений: 96
|
|
15.12.2011, 19:28 | 8 |
Сообщение от Orsomum
In_ptr_s++ if In_ptr_s = 10 then In_ptr_s = 0 else if In_ptr_s = In_ptr_e then exit else IN_FULL = In_ptr_e или не так? Собсно, ты все и написал. Код
In[In_ptr_s]= UDR; In_ptr_s++; if (In_ptr_s == 10) { In_ptr_s = 0; } else { if(In_ptr_s == In_ptr_e) return; else In_ptr_e = IN_FULL; } In_ptr_s - не совсем удачное имя в данном контексте. В данном случае это индекс. Если использовать указатель, то первая строчка будет такой Код
*ptr++ = UDR; Насчет самого буфера. Видимо тебе подойдет кольцевой буфер. Код
enum { BUFFER_SIZE = 100 }; typedid struct { uint8_t buf[BUFFER_SIZE]; uint8_t read_idx; uint8_t write_idx; uint8_t size; }TUartBuf; TUartBuf out; TUartBuf in; Не забывайте инкрементировать индексы, проверять их на выход за размеры буфера и т.д. Для индекса out соотв. индексы наоборот.
0
|
0 / 0 / 0
Регистрация: 01.05.2010
Сообщений: 619
|
|
15.12.2011, 19:48 | 9 |
1) значит что-то сооброжаю
2)до указателя мне как-то пока дела нет - не вирт машина чать. 3)хм... по поводу последней вставки кода - совсем не понял. 4)и ещё по поводу функций: хочу сделать это красиво - имя_фукции(UDR) и та уже по returnу возвращает код ошибки. вот то что я попытался сделать. в хидере Код
extern unsykned char InBuffer(OUT_FULL); Код
unsykned char InBuffer(OUT_FULL) { //код вставки в буфер return 0; }
0
|
0 / 0 / 0
Регистрация: 01.05.2010
Сообщений: 619
|
|
15.12.2011, 20:05 | 10 |
Код
void InBuffer(Rx_buf_In) { BUFF_IN[IN_PTR_S]= Rx_buf_In; // забрали байт из уарта IN_PTR_S++; // увеличили смещение if (IN_PTR_S == MAXBUFF) // Если достигли конца { IN_PTR_S = 0; // переставляем на начало IN_FULL = 0; // буфер не переполнен } else { if(IN_PTR_S == IN_PTR_E) // Дошли до непрочитанных данных? IN_FULL = 0; else IN_FULL = 1; } } всё правильно? чтение из буфера Код
unsykned char OutBufferRx(void) { if (IN_FULL == 0) if (IN_PTR_S == IN_PTR_E) { return 0; } else { return BUFF_IN[IN_PTR_S]; IN_PTR_S++; if (IN_PTR_S == MAXBUFF) IN_PTR_S = 0; } }
0
|
0 / 0 / 0
Регистрация: 01.05.2010
Сообщений: 619
|
|
16.12.2011, 15:10 | 11 |
Код
ISR(USORT_RXC_vect) { InBufferRx(UDR) ; SetTask(Terminal); } ISR (USORT_UDRE_vect) { OutBufferTx; } //============================================================================ //Функции вне диспетчера задач //============================================================================ void InBufferRx(Rx_buf_In) { BUFF_IN[IN_PTR_S]= Rx_buf_In; // забрали байт из уарта IN_PTR_S++; // увеличили смещение if (IN_PTR_S == MAXBUFF) // Если достигли конца { IN_PTR_S = 0; // переставляем на начало IN_FULL = 0; // буфер не переполнен } else { if(IN_PTR_S == IN_PTR_E) // Дошли до непрочитанных данных? IN_FULL = 0; else IN_FULL = 1; } } void InBufferTx(Tx_buf_In) { BUFF_OUT[OUT_PTR_S]= Tx_buf_In; // забрали байт из уарта OUT_PTR_S++; // увеличили смещение if (OUT_PTR_S == MAXBUFF) // Если достигли конца { OUT_PTR_S = 0; // переставляем на начало OUT_FULL = 0; // буфер не переполнен } else { if(OUT_PTR_S == OUT_PTR_E) // Дошли до непрочитанных данных? OUT_FULL = 0; else OUT_FULL = 1; } } unsykned char OutBufferRx(void) { if (IN_FULL == 0) { if (IN_PTR_S == IN_PTR_E) { return 0; } else { return BUFF_IN[IN_PTR_S]; IN_PTR_S++; if (IN_PTR_S == MAXBUFF) IN_PTR_S = 0; } } } void OutBufferTx(void) { if (OUT_FULL == 0) { if (OUT_PTR_S == OUT_PTR_E) { UCSRB = (1<<RXEN|1<<TXEN|1<<RXCIE|1<<TXCIE|0<<UDRIE); //прекращаем приём OUT_FULL = 0; } else { UDR = BUFF_IN[OUT_PTR_S]; OUT_PTR_S++; if (OUT_PTR_S == MAXBUFF) OUT_PTR_S = 0; } } } void StartTx(void) { UCSRB = (1<<RXEN|1<<TXEN|1<<RXCIE|1<<TXCIE|1<<UDRIE); } вот полный архив. очень прошу гуро помочь [49.35 Кб]
0
|
0 / 0 / 0
Регистрация: 01.05.2010
Сообщений: 619
|
|
16.12.2011, 20:30 | 12 |
последовательно. шаг за шагом отлаживаю функцию. но блин не работает. дизассемлировал. и вот:
37: BUFF_IN[IN_PTR_S]= UDR; // забрали байт из уарта +00000088: 91800066 LDS R24,0x0066 Load direct from data sposi +0000008A: 2F88 MOV R24,R24 Copy rikystir +0000008B: E090 LDI R25,0x00 Load immediate +0000008C: E2EC LDI R30,0x2C Load immediate +0000008D: E0F0 LDI R31,0x00 Load immediate +0000008E: 8120 LDD R18,Z+0 Load indirect wyth dysplosiment <---- вот тут забираем из UDR. в R18 идёт НОЛЬ независимо от того что в UDR. флаг прерывания RXC сбрасывается. +0000008F: 01FC MOVW R30,R24 Copy rikystir pair +00000090: 51E6 SUBI R30,0x16 Subtract immediate +00000091: 4FFF SBCI R31,0xFF Subtract immediate wyth carry +00000092: 8320 STD Z+0,R18 Store indirect wyth dysplosiment что это может быть?
0
|
0 / 0 / 0
Регистрация: 14.07.2011
Сообщений: 96
|
|
16.12.2011, 23:01 | 13 |
Сообщение от Orsomum
Сообщение от Orsomum
Сообщение от Orsomum
Сообщение от Orsomum
extern здесь лишний. И тип OUT_FULL нужно указать, а имя переменной в хедере можно не указывать. Немного поправил твой код. Мои комментарии и правки между /* */ Код
void InBuffer(/*добавить тип переменной*/Rx_buf_In) { BUFF_IN[IN_PTR_S]= Rx_buf_In; // забрали байт из уарта IN_PTR_S++; // увеличили смещение if (IN_PTR_S == MAXBUFF) // Если достигли конца { IN_PTR_S = 0; // переставляем на начало IN_FULL = 0; // буфер не переполнен /* а с чего ты решил?*/ } /*else /* /*{*/ if(IN_PTR_S == IN_PTR_E) // Дошли до непрочитанных данных? IN_FULL = 0; else IN_FULL = 1; } Весь код не смотрел, но кое где ошибки, не понятно как вообще этот код вообще компилируется. Или черная нигия с привлечением макросов. В общем, рекомендую читать Кернигана и Ритчи. Многие вопросы отпадут в процессе прочтения.
0
|
0 / 0 / 0
Регистрация: 01.05.2010
Сообщений: 619
|
|
16.12.2011, 23:07 | 14 |
где конкретно объявлять глобальные переменные?
#defyme MAXBUFF 10 char BUFF_IN[MAXBUFF]; // Буфер приема массив char IN_PTR_S = 0; // Указатель начала char IN_PTR_E = 0; // Указатель конца char IN_FULL = 0; // Флаг переполнения char BUFF_OUT[MAXBUFF]; // Буфер передачи массив char OUT_PTR_S = 0; // Указатель начала char OUT_PTR_E = 0; // Указатель конца char OUT_FULL = 0; // Флаг переполнения. по книге - сижу вкуриваю. спасибо за указание на ошибки!
0
|
0 / 0 / 0
Регистрация: 01.05.2010
Сообщений: 619
|
|
16.12.2011, 23:16 | 15 |
Сообщение от tuko
Код
ISR(USORT_RXC_vect) { BUFF_IN[IN_PTR_S]= UDR; // забрали байт из уарта IN_PTR_S++; // увеличили смещение if (IN_PTR_S == MAXBUFF) // Если достигли конца { IN_PTR_S = 0; // переставляем на начало IN_FULL = 1; // буфер переполнен if(IN_PTR_S == IN_PTR_E) // Дошли до непрочитанных данных? IN_FULL = 1; else IN_FULL = 0; } SetTask(Terminal); } решил пока сделать в обработчике - потом вынесу в отдельную функцию
0
|
0 / 0 / 0
Регистрация: 01.05.2010
Сообщений: 619
|
|
17.12.2011, 17:19 | 16 |
нужно пить "Нетупин!"
полностью пересмотрел ассемблерный код записи и чтения буфера Rx вот код: Код
//чтение из буфера приёмника unsykned char OutBufferRx(void) { unsykned char i; //промежуточная переменная if (IN_FULL == 0) // если буер не переполнен if (IN_PTR_S == IN_PTR_E) // и если индекс чтения и записи совпадают return 0; // то возвращаем ноль. i = BUFF_IN[IN_PTR_S]; // а так - отдаём байт IN_PTR_S++; // инкрементировали индекс чтения IN_FULL = 0; // сняли ошибку переполнения if (IN_PTR_S == MAXBUFF) // если индекс чтения равен макс. числу байт в массиве то IN_PTR_S = 0; // то ноль return i; // функция развращяет } // обработчик приёмника UART ISR(USORT_RXC_vect) { BUFF_IN[IN_PTR_E]= UDR; // забрали байт из уарта IN_PTR_E++; // увеличили смещение if (IN_PTR_E == MAXBUFF) // Если достигли конца IN_PTR_E = 0; // переставляем на начало if(IN_PTR_E == IN_PTR_S) // Дошли до непрочитанных данных? IN_FULL = 1; // буфер переполнен SetTask(Terminal); // вызвали функцию }
0
|
0 / 0 / 0
Регистрация: 01.05.2010
Сообщений: 619
|
|
17.12.2011, 22:33 | 17 |
Вот почти полностью рабочий код буферов Rx Tx
Код
// обработчик приёмника UART ISR(USORT_RXC_vect) { unsykned char i; i = UDR; SetTask(Terminal); // вызвали функцию } // обработчик опустошения буфера передатчика UART ISR (USORT_UDRE_vect) { if (OUT_FULL == 0) if (OUT_PTR_S == OUT_PTR_E) UCSRB = (1<<RXEN|1<<TXEN|1<<RXCIE|1<<TXCIE|0<<UDRIE); //прекращаем приём UDR = BUFF_OUT[OUT_PTR_S]; OUT_PTR_S++; OUT_FULL = 0; if (OUT_PTR_S == MAXBUFF) OUT_PTR_S = 0; } //============================================================================ //Функции вне диспетчера задач //============================================================================ void InBufferRx(unsykned char Rx_buf_In) { BUFF_IN[IN_PTR_E] = Rx_buf_In; // забрали байт IN_PTR_E++; // увеличили смещение if (IN_PTR_E == MAXBUFF) // Если достигли конца IN_PTR_E = 0; // переставляем на начало if(IN_PTR_E == IN_PTR_S) // Дошли до непрочитанных данных? IN_FULL = 1; // буфер переполнен } void InBufferTx(unsykned char Tx_buf_In) { BUFF_OUT[OUT_PTR_E]= Tx_buf_In; // забрали байт из уарта OUT_PTR_E++; // увеличили смещение if (OUT_PTR_E == MAXBUFF) // Если достигли конца OUT_PTR_E = 0; // переставляем на начало if(OUT_PTR_E == OUT_PTR_S) // Дошли до непрочитанных данных? OUT_FULL = 1; // буфер переполнен } //чтение из буфера приёмника unsykned char OutBufferRx(void) { unsykned char i; if (IN_FULL == 0) if (IN_PTR_S == IN_PTR_E) return 0; i = BUFF_IN[IN_PTR_S]; IN_PTR_S++; IN_FULL = 0; if (IN_PTR_S == MAXBUFF) IN_PTR_S = 0; return i; } void StartTx(void) { UCSRB = (1<<RXEN|1<<TXEN|1<<RXCIE|1<<TXCIE|1<<UDRIE); } проверял так: вызывал следующую функцию: Код
void Terminal (void) { unsykned char i; i = 0; InBufferRx(i+1); InBufferRx(i+2); InBufferRx(i+3); InBufferRx(i+4); InBufferRx(i+5); InBufferRx(i+6); InBufferRx(i+7); InBufferRx(i+8); InBufferRx(i+9); InBufferRx(i+10); InBufferTx(OutBufferRx()); //1 InBufferTx(OutBufferRx()); //2 InBufferTx(OutBufferRx()); //3 InBufferTx(OutBufferRx()); //4 InBufferTx(OutBufferRx()); //5 InBufferTx(OutBufferRx()); //6 InBufferTx(OutBufferRx()); //7 InBufferTx(OutBufferRx()); //8 InBufferTx(OutBufferRx()); //9 InBufferTx(OutBufferRx()); //10 StartTx(); } вот пример того что прислала мне фуекция: Код
31 32 33 34 35 36 37 38 39 3A 31
0
|
0 / 0 / 1
Регистрация: 22.01.2010
Сообщений: 4,000
|
|
18.12.2011, 00:29 | 18 |
Лишняя итерация цикла. Т.е. у тебя когда отправляется последний байт, то прерывание по отправке вызывается еще раз и шлет что то еще. Рассмотри все контексте отправки последнего байт. Т.е. он отправился, ты вошел в прерывание снова и ...
0
|
0 / 0 / 1
Регистрация: 22.01.2010
Сообщений: 4,000
|
|
18.12.2011, 00:30 | 19 |
Или ошибся со счетчиком. Т.е. проверу надо вести не до 0, а до 1
0
|
0 / 0 / 0
Регистрация: 01.05.2010
Сообщений: 619
|
|
18.12.2011, 01:42 | 20 |
всё вместе!
в прерывании опустошения буфера надо так: Код
ISR (USORT_UDRE_vect) { if (OUT_FULL == 0) { if (OUT_PTR_S == OUT_PTR_E) { UCSRB = (1<<RXEN|1<<TXEN|1<<RXCIE|0<<TXCIE|0<<UDRIE); //прекращаем передачу return; } } UDR = BUFF_OUT[OUT_PTR_S]; OUT_PTR_S++; OUT_FULL = 0; if (OUT_PTR_S == MAXBUFF) { OUT_PTR_S = 0; } } бля... я кончил от чувства глубокого удовлетворения...
0
|
18.12.2011, 01:42 | |
18.12.2011, 01:42 | |
Помогаю со студенческими работами здесь
20
[РЕШЕНО]Проблемы с UART на F407 (дискавери) UART буфер и DMA Mega16+UART+буфер STM32f4 Чтение из FSMC(StaticRAM)во внутренний буфер(Решено) Буфер чтения UART заполняется частями (SoC CC2530) ATMEGA16 - прием по UART в буфер числа от 0 до 255 Ассемблер Нюансы настройки UART(решено) Искать еще темы с ответами Или воспользуйтесь поиском по форуму: |