American English British English Български Čeština Français Deutsch (Du) Magyar Italiano 日本語 Lietuvių Polski Српски Slovenčina Español (Tú) Türkçe Українська
Select language:

Программирование на СИ. Помощь в написании кода.

<<

alvikagal

User avatar

Posts: 2765

Joined: 18 Sep 2013, 01:58

Location: Украина, Павлоград

Your CAR: ВАЗ-21099 1,5л.

SECU version: DIY SECU-3T


Has thanked: 333 times
Been thanked: 449 times

Post 09 Sep 2015, 18:06

Программирование на СИ. Помощь в написании кода.

Всем привет.
Обращаюсь к опытным программистам, а так же к начинающим.
Если Вам будет не сложно, то заходите в эту тему, чтобы помогать и исправлять ошибки начинающих писак кода, чтобы меньше было говнокода ;) .
За ранее всем участникам спасибо.


Пишу для ATmega8 в AtmelStudio (вернее собираю прошивку в нём, а пишу в Notepad++).
Сейчас изучаю приём/передачу данных по UART.
Стояла задача передать массив с 16 битными данными. С передачей массива немного разобрался, но вот передавать 16 бит через 8 битный буфер зашёл в тупик. Передаю только 8 бит данных из массива.
Как передавать 16 бит?
Пока решил таким способом.
Вот код:
  Code:
#define F_CPU 1000000UL    // 1 MHz
#include <avr/io.h>
#include <uart.h>
#include <util/delay.h>
 
#define FOSC 1000000L      //Тактовая частота
#define BAUD 4800L          //Скорость порта
#define MYUBRR FOSC/16/BAUD-1
 
void USART_Transmit(void);
void USART_Init( unsigned int ubrr);
 
uint16_t Massiv [16]      = {0,1,2,3,4,5,6,7,8,9,10,11,24,255,256,1140};   // массив 2 байтых данных
 
//Функция отправки данных
void USART_Transmit(void)
{
   for (int i=0;i<16;i++)
      {
         uint16_t Temp=Massiv[i];
         uint8_t TempH=Temp>>8;
         uint8_t TempL=Temp;
         while (!(UCSRA & (1<<UDRE))); //Ожидание опустошения буфера приема         
         UDR=TempH;
         while (!(UCSRA & (1<<UDRE))); //Ожидание опустошения буфера приема         
         UDR=TempL;
      }   
}
 
//Инициализация модуля USART
void USART_Init( unsigned int ubrr)
{
//Задаем скорость работы USART
UBRRH = (unsigned char)(ubrr>>8);
UBRRL = (unsigned char)ubrr;

UCSRB = (1<<TXEN); //разрешёна передача
 
UCSRC=(1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);
}

int main(void)
{
USART_Init (MYUBRR);

while(1)//вечный цикл
{
   USART_Transmit();
   _delay_ms(1000);
}   
}


Вот, что получилось:
60-2/SECU/ДКЗ/бенз-газ/ДД/ДТВ/УДК/ШДГ/ВЗ
Отчёт - viewtopic.php?f=6&t=236
Бортовой компьютер 20*04 - viewtopic.php?p=19996#p19996
SD card logger - viewtopic.php?f=12&t=1029
<<

STC

User avatar

Posts: 6536

Joined: 30 Apr 2013, 23:41

Location: Ukraine

Your CAR: AZLK 2140

SECU version: DIY SECU-3


Has thanked: 800 times
Been thanked: 1317 times

Post 09 Sep 2015, 20:24

Re: Программирование на СИ. Помощь в написании кода.

  Code:
uint8_t TempH=Temp>>8;
uint8_t TempL=Temp;


Все правильно сделал.
Author of the SECU-3™ project http://SECU-3.org. An open source engine control unit / Ignition control system, (C) 2007.
Клуб проекта в Facebook https://www.facebook.com/groups/secu3club
Клуб проекта ВКонтакте https://vk.com/secu3club (вступаем!)
<<

KOT

User avatar

Posts: 328

Joined: 10 May 2013, 14:23

Location: Запорожье


Has thanked: 6 times
Been thanked: 85 times

Post 10 Sep 2015, 11:02

Re: Программирование на СИ. Помощь в написании кода.

Лично мне не нравится этот код, ожиданием пока освободится буфера. Лучше использовать прерывание по опустошению буфера передачи, в нем обрабатывать передачу массива.
Еще никто не дает гарантии, что компилятор не сделает сдвиг вправо 8 раз, а не воспользуется взятием старшего регистра; uint8_t TempH=Temp>>8;
Но это смотря для чего программа, недавно корректировал прошивку так там вобще общение по USB через прерывания, программная задержка и вычитка данных с нескольких датчиков 1-wire и работает)).

Еще мне не особо нравится как компилятор winAVR работает с флешь памятью больше 64 килобайт, с ИАРом попроще и ИАР создает более читабельный ассемблерный код, если нужно посмотреть че натвроил.

Протеус для отладки очень помогает, но меня ввел в ступор, когда не работал режим спячки, верней он там есть но временные интервалы хаотичны, а в железе все в порядке.

ПС сам только недавно пишу на СИ, до этого долгие трудные годы ассемблерного кода :D
Если что пишите в ЛС - там быстрей отвечу, чем смогу помогу.
Машина ЗАЗ 1103i, ГБО4. Управление ДВС: аналог Secu-3 и MegasquirtAVR модифицированное железо и своя прошивка.
<<

STC

User avatar

Posts: 6536

Joined: 30 Apr 2013, 23:41

Location: Ukraine

Your CAR: AZLK 2140

SECU version: DIY SECU-3


Has thanked: 800 times
Been thanked: 1317 times

Post 10 Sep 2015, 11:30

Re: Программирование на СИ. Помощь в написании кода.

Лично мне не нравится этот код, ожиданием пока освободится буфера. Лучше использовать прерывание по опустошению буфера передачи, в нем обрабатывать передачу массива.

Однозначно, но человек только учится. Использование прерываний будет следующим этапом развития программы.

Еще никто не дает гарантии, что компилятор не сделает сдвиг вправо 8 раз, а не воспользуется взятием старшего регистра; uint8_t TempH=Temp>>8;

Оптимизатор кода современных компиляторов работает четко, он не будет сдвигать 8 раз, он просто возьмет 2-й байт. Если не хочется сдвигать, то можно взять адрес, привести к указателю на uint8_t*, затем прибавить нужное число для смещения и взять значение по указателю. Вот так у меня сделано:
  Code:
#define _AB(src,rel) *(((unsigned char*)&(src)+(rel)))

Макрос берет значение N-го байта в указанной переменной.
Author of the SECU-3™ project http://SECU-3.org. An open source engine control unit / Ignition control system, (C) 2007.
Клуб проекта в Facebook https://www.facebook.com/groups/secu3club
Клуб проекта ВКонтакте https://vk.com/secu3club (вступаем!)
<<

Samtorr

User avatar

Posts: 136

Joined: 16 Jun 2015, 21:45

Your CAR: Golf II 1.3i

SECU version: DIY SECU-3T


Has thanked: 6 times
Been thanked: 75 times

Post 10 Sep 2015, 12:19

Re: Программирование на СИ. Помощь в написании кода.

Есть еще несколько более хитрый вариант, но с подобными фокусами надо быть внимательным:
  Code:
#define F_CPU 1000000UL    // 1 MHz
#include <avr/io.h>
//#include <uart.h>
#include <util/delay.h>

#define FOSC 1000000L      //Тактовая частота
#define BAUD 4800L          //Скорость порта
#define MYUBRR FOSC/16/BAUD-1

void USART_Transmit(uint16_t*, uint8_t);
void USART_Init( unsigned int);

#define ARR_SIZE 16
uint16_t Massiv [ARR_SIZE]      = {0,1,2,3,4,5,6,7,8,9,10,11,24,255,256,1140};   // массив 2 байтых данных


//Функция отправки данных
void USART_Transmit(uint16_t* array_16bit, uint8_t arr_size_8bit)
{
   uint8_t * ptr_arr =(uint8_t*) array_16bit;
   for (uint8_t i=0;i<arr_size_8bit-1;i++)
   {
   
      while (!(UCSRA & (1<<UDRE))); //Ожидание опустошения буфера приема
      UDR=*(ptr_arr+i);
      
   }
}

//Инициализация модуля USART
void USART_Init( unsigned int ubrr)
{
   //Задаем скорость работы USART
   UBRRH = (unsigned char)(ubrr>>8);
   UBRRL = (unsigned char)ubrr;

   UCSRB = (1<<TXEN); //разрешёна передача
   
   UCSRC=(1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0);
}

int main(void)
{
   USART_Init (MYUBRR);

   while(1)//вечный цикл
   {
      USART_Transmit(Massiv,sizeof(Massiv));
      _delay_ms(1000);

   }
}
<<

alvikagal

User avatar

Posts: 2765

Joined: 18 Sep 2013, 01:58

Location: Украина, Павлоград

Your CAR: ВАЗ-21099 1,5л.

SECU version: DIY SECU-3T


Has thanked: 333 times
Been thanked: 449 times

Post 10 Sep 2015, 15:52

Re: Программирование на СИ. Помощь в написании кода.

КОТ, спасибо. Без коментов мне пока сложно понять что написано ;-) . Сам стараюсь пока писать коменты, чтобы не забыть, что написал.
Насчёт прерывания уже думал. В подпрограмме передачи разрешать прерывание по UDR, по завершению передачи отключать прерывание. Попробую, как время будет.

Насчёт ИАР тоже мечтаю им собирать прошивку, но надо разобраться как им собирать, всё установлено т.к. для Secu им собираю.
60-2/SECU/ДКЗ/бенз-газ/ДД/ДТВ/УДК/ШДГ/ВЗ
Отчёт - viewtopic.php?f=6&t=236
Бортовой компьютер 20*04 - viewtopic.php?p=19996#p19996
SD card logger - viewtopic.php?f=12&t=1029
<<

STC

User avatar

Posts: 6536

Joined: 30 Apr 2013, 23:41

Location: Ukraine

Your CAR: AZLK 2140

SECU version: DIY SECU-3


Has thanked: 800 times
Been thanked: 1317 times

Post 10 Sep 2015, 18:57

Re: Программирование на СИ. Помощь в написании кода.

Выкладываю готовый пример обработки UART при помощи прерываний c буферизацией приемника и передатчика (только бери да читай или подкидывай байты из/в очередь). Пример называется AVR306.
Attachments
avr306.zip
(7.38 KiB) Downloaded 40 times
AVR306-Using-the-AVR-UART-in-C.pdf
Sample software from atmel.com
(62.91 KiB) Downloaded 161 times
Author of the SECU-3™ project http://SECU-3.org. An open source engine control unit / Ignition control system, (C) 2007.
Клуб проекта в Facebook https://www.facebook.com/groups/secu3club
Клуб проекта ВКонтакте https://vk.com/secu3club (вступаем!)
<<

KOT

User avatar

Posts: 328

Joined: 10 May 2013, 14:23

Location: Запорожье


Has thanked: 6 times
Been thanked: 85 times

Post 10 Sep 2015, 23:44

Re: Программирование на СИ. Помощь в написании кода.

Мои грабли начинающего:

Есть нюансы к примеру при передачи данных из флешь памяти контроллера, нужно писать отдельно функцию.
И когда я пытался передавать данные их меги128, которые находились в конце флешь памяти и компилировать это все ВинАВР то чуть себе мозг не сламал. В итоге заработало, но сколько же нужно работать руками и головой в ВинАВР меня смутило. Но впрочем че жаловатся на бесплатных компилятор.

К стати еще советую почитать про переменные типа volatile - без низ в прерываниях никак, как-то была ссылка но сейчас не могу найти про их описание. Там дело в то что компилятор грубо говоря не знает что такое прерывание, и если в прерывании будет менятся переменная, то она должна быть типа volatile, иначе компиль может вырезать кусок кода. Еще советую обратить внимание на атомарный доступ к переменным - нужно запрещать и разрешать прерывания, когда работаешь с битами или 16 битными и более значениями. Еще на мой взгляд не стоит пользоватся встроенными библитеками преобразования данных - очень долго выполняется.

О к стати у меня тоже вопрос: как сделать округление до целого при делении, чтоб ИАР не выполнял повторное деление? Проблема такова, либо нужно пользоватся функцией div, ldiv, в которой по умолчанию есть остаток от деления
ldiv_t res = ldiv(a, b);
if (res.rem > (b>>1)) res.quot++;
В первом случае недостаток если я хочу поделить 32 битно на 8 битное число и округлить, то из за встроеной либы я буду делить 32 на 32 бита

либо uint32_t rem = a % b;
uint32_t result = a / b;
if (rem > (b>>1)) result++;
Но в последнем случае ИАР выполняет деление 2 раза. Но может быть (нет никаких гарантий) ИАР будет делить 32 на 8 битное число.

Выход я конечно нашел - сделал асемблерную вставку и передавал ей указатель на структуру, но про переносимость кода можно забыть.
Машина ЗАЗ 1103i, ГБО4. Управление ДВС: аналог Secu-3 и MegasquirtAVR модифицированное железо и своя прошивка.
<<

Samtorr

User avatar

Posts: 136

Joined: 16 Jun 2015, 21:45

Your CAR: Golf II 1.3i

SECU version: DIY SECU-3T


Has thanked: 6 times
Been thanked: 75 times

Post 11 Sep 2015, 09:33

Re: Программирование на СИ. Помощь в написании кода.

KOT wrote:О к стати у меня тоже вопрос: как сделать округление до целого при делении, чтоб ИАР не выполнял повторное деление?

Если правильно помню, что-то вроде:
  Code:
uint32_t result = (a+(b>>1))/b;

Только если числа знаковые, надо быть внимательным, есть нюансы
<<

KOT

User avatar

Posts: 328

Joined: 10 May 2013, 14:23

Location: Запорожье


Has thanked: 6 times
Been thanked: 85 times

Post 11 Sep 2015, 19:51

Re: Программирование на СИ. Помощь в написании кода.

О спасибо, нужно попробовать. Знаковых чисел пока боюсь, для меня мне каждый раз за справочником нужно лезть что понять в каком случае как преобразовываются числа.
Машина ЗАЗ 1103i, ГБО4. Управление ДВС: аналог Secu-3 и MegasquirtAVR модифицированное железо и своя прошивка.
Next

Return to Решение проблем. Новичкам сюда!

Who is online

Users browsing this forum: No registered users and 2 guests

cron
Powered by phpBB® Forum Software © phpBB Group.