Select language:

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

<<

alvikagal

Аватара пользователя

Сообщения: 2525

Зарегистрирован: 18 сен 2013, 01:58

Откуда: Украина, Павлоград

Машина: ВАЗ-21099 1,5л.

Версия SECU: самодельная SECU-3T


Благодарил (а): 312 раз.
Поблагодарили: 413 раз.

Сообщение 09 сен 2015, 18:06

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

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


Пишу для ATmega8 в AtmelStudio (вернее собираю прошивку в нём, а пишу в Notepad++).
Сейчас изучаю приём/передачу данных по UART.
Стояла задача передать массив с 16 битными данными. С передачей массива немного разобрался, но вот передавать 16 бит через 8 битный буфер зашёл в тупик. Передаю только 8 бит данных из массива.
Как передавать 16 бит?
Пока решил таким способом.
Вот код:
  Код:
#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

Аватара пользователя

Сообщения: 5893

Зарегистрирован: 30 апр 2013, 23:41

Откуда: Ukraine

Машина: AZLK 2140

Версия SECU: самодельная SECU-3


Благодарил (а): 722 раз.
Поблагодарили: 1164 раз.

Сообщение 09 сен 2015, 20:24

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

  Код:
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

Аватара пользователя

Сообщения: 328

Зарегистрирован: 10 май 2013, 14:23

Откуда: Запорожье


Благодарил (а): 6 раз.
Поблагодарили: 85 раз.

Сообщение 10 сен 2015, 11:02

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

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

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

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

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

STC

Аватара пользователя

Сообщения: 5893

Зарегистрирован: 30 апр 2013, 23:41

Откуда: Ukraine

Машина: AZLK 2140

Версия SECU: самодельная SECU-3


Благодарил (а): 722 раз.
Поблагодарили: 1164 раз.

Сообщение 10 сен 2015, 11:30

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

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

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

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

Оптимизатор кода современных компиляторов работает четко, он не будет сдвигать 8 раз, он просто возьмет 2-й байт. Если не хочется сдвигать, то можно взять адрес, привести к указателю на uint8_t*, затем прибавить нужное число для смещения и взять значение по указателю. Вот так у меня сделано:
  Код:
#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

Аватара пользователя

Сообщения: 136

Зарегистрирован: 16 июн 2015, 21:45

Машина: Golf II 1.3i

Версия SECU: самодельная SECU-3T


Благодарил (а): 6 раз.
Поблагодарили: 74 раз.

Сообщение 10 сен 2015, 12:19

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

Есть еще несколько более хитрый вариант, но с подобными фокусами надо быть внимательным:
  Код:
#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

Аватара пользователя

Сообщения: 2525

Зарегистрирован: 18 сен 2013, 01:58

Откуда: Украина, Павлоград

Машина: ВАЗ-21099 1,5л.

Версия SECU: самодельная SECU-3T


Благодарил (а): 312 раз.
Поблагодарили: 413 раз.

Сообщение 10 сен 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

Аватара пользователя

Сообщения: 5893

Зарегистрирован: 30 апр 2013, 23:41

Откуда: Ukraine

Машина: AZLK 2140

Версия SECU: самодельная SECU-3


Благодарил (а): 722 раз.
Поблагодарили: 1164 раз.

Сообщение 10 сен 2015, 18:57

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

Выкладываю готовый пример обработки UART при помощи прерываний c буферизацией приемника и передатчика (только бери да читай или подкидывай байты из/в очередь). Пример называется AVR306.
Вложения
avr306.zip
(7.38 КБ) Скачиваний: 33
AVR306-Using-the-AVR-UART-in-C.pdf
Sample software from atmel.com
(62.91 КБ) Скачиваний: 151
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

Аватара пользователя

Сообщения: 328

Зарегистрирован: 10 май 2013, 14:23

Откуда: Запорожье


Благодарил (а): 6 раз.
Поблагодарили: 85 раз.

Сообщение 10 сен 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

Аватара пользователя

Сообщения: 136

Зарегистрирован: 16 июн 2015, 21:45

Машина: Golf II 1.3i

Версия SECU: самодельная SECU-3T


Благодарил (а): 6 раз.
Поблагодарили: 74 раз.

Сообщение 11 сен 2015, 09:33

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

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

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

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

KOT

Аватара пользователя

Сообщения: 328

Зарегистрирован: 10 май 2013, 14:23

Откуда: Запорожье


Благодарил (а): 6 раз.
Поблагодарили: 85 раз.

Сообщение 11 сен 2015, 19:51

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

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

Вернуться в Решение проблем. Новичкам сюда!

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 3

Powered by phpBB® Forum Software © phpBB Group.