Обсуждаем контроллеры компании Atmel.
Ответить

Re: Нескольно простых вопросов о программировании AVR на Си.

Пн июн 05, 2023 12:48:52

А зачем такие сложности? Почему нельзя просто UCSR0C = 0x06;
Там же нет битов, которые меняются в процессе работы, и которые можно испортить. Я как понял, это никакая не битовая операция, а как записать байт в регистр идиотским способом.

Re: Нескольно простых вопросов о программировании AVR на Си.

Пн июн 05, 2023 13:41:33

Eто целый стиль прогр. кода для AVR. Например, мне всегда удивляет DATA = ... | (0 << NNN). Кто пишет так, как привык. Важен результат, а к чужому стилю привыкаешь быстро.

Пример из TinyI2C:
Код:
USICR = 0<<USISIE | 0<<USIOIE | 1<<USIWM1 | 0<<USIWM0 | 1<<USICS1 | 0<<USICS0 | 1<<USICLK | 0<<USITC;

Re: Нескольно простых вопросов о программировании AVR на Си.

Пн июн 05, 2023 15:52:37

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

Re: Нескольно простых вопросов о программировании AVR на Си.

Пн июн 05, 2023 20:01:25

А зачем такие сложности? Почему нельзя просто UCSR0C = 0x06;
можно. и иногда я так делаю, если пишу для себя и предполагаю, что никогда не вернусь к этому. И если придется возвращаться, то вспомнить, что такое 0x06 мне невозможно, и будет потеря времени на проверку, что здесь включено, есть четность или нет, 7 или 8 бит и т.д.

Re: Нескольно простых вопросов о программировании AVR на Си.

Вт июн 06, 2023 13:11:50

я делаю как ненормальные... но указываю все биты в т.ч. и 0е, и обычно дефайню значения для удобочитаемости (получается вроде таблицы алгоритм-билдера)
но! небольшая проблема возникает когда один параметр растянут на 2 регистра (напрямую писать уже не получится, но дефайн при этом использовать по прежнему можно, правда конструкции выходят витиеватые - пример регистр WGM1 в tiny2313)
СпойлерИзображение
Код:
// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: 1200,000 kHz
#define _CS1    1
// Mode: CTC top=OCR1A
#define _WGM1   4
// OC1A output: Disconnected
#define _COM1A  0
// OC1B output: Disconnected
#define _COM1B  0
// Noise Canceler: Off
#define _ICNC1  0
// Input Capture on Falling Edge
#define _ICES1  0
// Timer1 Overflow Interrupt: Off
#define _TOIE1  0
// Input Capture Interrupt: Off
#define _ICIE1  0
// Compare A Match Interrupt: Off
#define _OCIE1A 0
// Compare B Match Interrupt: Off
#define _OCIE1B 0



// Timer/Counter 1 initialization
TCCR1A=(_COM1A<<COM1A0) | (_COM1B<<COM1B0) | ((_WGM1&3)<<WGM10);
TCCR1B=(_ICNC1<<ICNC1) | (_ICES1<<ICES1) | ((_WGM1>>2)<<WGM12) | (_CS1<<CS10);
// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=(_TOIE1<<TOIE1) | (_OCIE1A<<OCIE1A) | (_OCIE1B<<OCIE1B) | (_ICIE1<<ICIE1) | (_OCIE0B<<OCIE0B) | (_TOIE0<<TOIE0) | (_OCIE0A<<OCIE0A);
а можно пойти ещё дальше и, добавив условную компиляцию, исключать из сборки содержащие нули регистры неподключаемой периферии...
пожалуй, как время появится, этим и займусь...

Добавлено after 7 hours 77 minutes 77 seconds:
Получится что-то такое, вынесенное в отдельный файл...
Спойлер
Код:
// Timer/Counter 1 initialization
#if defined(_COM1A) || defined(_COM1B) || defined(_WGM1)
    TCCR1A=0
    #ifdef _COM1A
        | (_COM1A<<COM1A0)
    #endif
    #ifdef _COM1B
        | (_COM1B<<COM1B0)
    #endif
    #ifdef _WGM1
        | ((_WGM1&0b11)<<WGM10)
    #endif
    ; 
#endif
#if defined(_ICNC1) || defined(_ICES1) || defined(_WGM1) || defined(_CS1)
    TCCR1B=0
    #ifdef _ICNC1
        | (_ICNC1<<ICNC1)
    #endif
    #ifdef _ICES1
        | (_ICES1<<ICES1) 
    #endif
    #ifdef _WGM1
        | ((WGM1>>2)<<WGM12)
    #endif
    #ifdef _CS1
        | (_CS1<<CS10)
    #endif
    ; 
#endif

останется проинициировать нужные биты и следом приинклюдить файл настройки периферии...

правда плохо то, что так у меня выйдет сделать только начальную настройку... :(
Вложения
1686022463926.jpg
(29.72 KiB) Скачиваний: 73

Re: Нескольно простых вопросов о программировании AVR на Си.

Вт июн 06, 2023 13:23:40

В последних выражениях много тавтологии - не упрощаем пользователю, а усложняем :P.
Код:
TCCR1B=(_ICNC1<<ICNC1) | (_ICES1<<ICES1) | ((_WGM1>>2)<<WGM12) | (_CS1<<CS10);
...
#ifdef _WGM1
  | ((WGM1>>2)<<WGM12)
#endif

Если бы у меня был выбор редактировать, я бы пропустил код даже для понимания :).
А если придется: следует полная замена/переписывание.

Re: Нескольно простых вопросов о программировании AVR на Си.

Вт июн 06, 2023 14:14:29

нет, этот код пользователь не увидит, для него настройка будет выглядеть так:
Спойлер
Код:
// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: 1200,000 kHz
#define _CS1    1
// Mode: CTC top=OCR1A
#define _WGM1   4
// OC1A output: Disconnected
#define _COM1A  0
// OC1B output: Disconnected
#define _COM1B  0
// Noise Canceler: Off
#define _ICNC1  0
// Input Capture on Falling Edge
#define _ICES1  0
// Timer1 Overflow Interrupt: Off
#define _TOIE1  0
// Input Capture Interrupt: Off
#define _ICIE1  0
// Compare A Match Interrupt: Off
#define _OCIE1A 0
// Compare B Match Interrupt: Off
#define _OCIE1B 0

#include <tiny2313_peripheral_init.c>
я хотел упростить эту тавтологию, (хоть она не очень то и мешает) но внутри дефайна не получилось применить условную компиляцию :(

Добавлено after 6 minutes 43 seconds:
оно, конечно, можно ещё приблизить к пользователю, если применять команды вида:
#define _NoiseCancellerOnTimer1Enabled
вместо
#define _ICNC1 1
но это и печатать больше и ещё кучу команд учить... :roll:

Добавлено after 1 minute 7 seconds:
Да и какой-то уж слишком ардуинообразный код получится... :kill:

Re: Нескольно простых вопросов о программировании AVR на Си.

Ср июл 12, 2023 09:29:39

Всем привет! Собрал я для своей дачи контроллер для озонирования воды, т.к. в воде много двухвалентного железа, его как то надо окислять, чтобы применять воду для бытовых нужд, озон лучше всего для этого подходит еще попутно очень хорошо обеззараживает воду. Вся система состоит из двух бочек, алгоритм таков: первую бочку скважный насос накачивает воду, после наполнения бочки включается циркуляционный насос и гоняет воду по кругу в первой бочке через эжектор Вентури, тем самым смешивает воду с озоном из озонатора 1 час(по таймеру), далее отстаивание воды 6 часов(по таймеру), далее перелив воды через электромагнитный клапан во вторую расходную бочку, откуда после наполения второй бочки третий насос с гидроаккамулятром подает воду в дом на разбор. Всем этим действием и управляет контроллер на atmega8. Решил прикрутить еще "собаку", ну мало ли завис, сбросит. Но тут же возникает вопрос из за незнания применения "собаки", к примеру зависло во время одного из действия когда считает таймер, "собака" сбросила, т.е. все сначало, весь счет таймера потерялся... как с этим быть, писать в энергонезависимую память раз в секунду/минуту какая часть программы выполнялась, счет таймера, ресурс быстро израсходую? писать все тоже самое отдельную память?

Re: Нескольно простых вопросов о программировании AVR на Си.

Ср июл 12, 2023 11:12:28

считать таймер в переменных, не очищаемых при сбросе МК

Re: Нескольно простых вопросов о программировании AVR на Си.

Ср июл 12, 2023 12:41:17

считать таймер в переменных, не очищаемых при сбросе МК

это каких? static?

Re: Нескольно простых вопросов о программировании AVR на Си.

Ср июл 12, 2023 13:13:53

Код:
uint8_t count __attribute__ ((section (".noinit")));

Re: Нескольно простых вопросов о программировании AVR на Си.

Ср июл 12, 2023 13:18:33

Код:
uint8_t count __attribute__ ((section (".noinit")));

Спсибо, пойду подтягивать теорию! :beer:

Re: Нескольно простых вопросов о программировании AVR на Си.

Ср июл 12, 2023 13:40:20

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

В самом дешёвом модуле RTC для ардуинки, в чипе DS1307 есть ещё и SRAM с питанием от батареи, 56 байт. Можно туда заливать текущее состояние, дублируя трижды, с учётом того, что МК может зависнуть во время записи. А при старте сравнивать все три сохранённых блока, если два идущих подряд совпали - можно их использовать для восстановления состояния.
Либо просто использовать время из RTC, типа "если сейчас от 01 до 06 часов утра - гонять воду в первом баке".

Re: Нескольно простых вопросов о программировании AVR на Си.

Пт июл 14, 2023 17:38:26

Код:
uint8_t count __attribute__ ((section (".noinit")));

и
ARV писал(а):считать таймер в переменных, не очищаемых при сбросе МК

Подскажите пожалуйста, скажем после сброса сторожевым таймером, мне скорее всего нужно в регистре управления MCUCSR два бита WDRF(Флаг индикации сброса сторожевым таймером) и PORF(Флаг Сброса включении питания), чтобы понимать МК как он именно сбросился. Потом, поняли что сторожевым таймером, биты сбросить в 0. Далее самое интересно, где это делаетcя int main?
нацарапал приблизительный пример:
Код:
#include "main.h"
#define F_CPU 8000000UL

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <avr/wdt.h>

uint8_t state_error __attribute__ ((section (".noinit")));
uint8_t state_status __attribute__ ((section (".noinit")));
uint8_t state_status_2 __attribute__ ((section (".noinit")));

void sensor(void);

int main(void)
{
   if(MCUCSR&(1<<WDRF)){ MCUCSR&=~(1<<WDRF);}
   if(MCUCSR&(1<<PORF)) {MCUCSR&=~(1<<PORF);}

   Port_Init();
   Timer_Init();

   sei();
   
   wdt_enable(WDTO_1S);
while (1) {
   wdt_reset();
   sensor(); //опрос датчиков уровня воды
   if(state_status == 1){
      PORTD |= (1<<RELAY_PUMP);   //вкл насос
   }else{
      PORTD &=~ (1<<RELAY_PUMP);  //выкл насос
   }
    }
}

Re: Нескольно простых вопросов о программировании AVR на Си.

Пт июл 14, 2023 18:44:03

Код:
int main(void)
{
  if (MCUCSR & (1 << PORF)) // вероятность этого сброса выше всех, пусть идет первым
  {
        MCUCSR&=(unsigned char)(~(1 << PORF));
       // делаем что должно при сбросе  "вкл-выкл питания"
  }
  else if (MCUCSR & (1 << WDRF))
  {
      MCUCSR&=(unsigned char)(~(1 << WDRF));
      // делаем что должно при сбросе "собакой"
  }
  else
  {
      // делаем что должно при ином сбросе
  }
   

Re: Нескольно простых вопросов о программировании AVR на Си.

Пн июл 17, 2023 10:34:35

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

разумеется, при установленном PORF надо инициализировать все .noinit переменные, т.к. в ином месте это делать нельзя.

Re: Нескольно простых вопросов о программировании AVR на Си.

Пн июл 17, 2023 11:01:31

Я тоже так подумал вначале. Но потом пришел к выводу, что сбрасывая сразу все биты в конце мы увеличим длину кода до их сброса (особенно если большая обработка причины сброса), а значит и вероятность сброса во время выполнения этого участка. И последующее определение причины сброса может оказаться неверным.

Re: Нескольно простых вопросов о программировании AVR на Си.

Пн июл 17, 2023 11:30:53

на сколько я помню, минимальное время WDT - около 15 мс, за это время можно столько кода выполнить... другое дело, что лучше проверять причину сброса в секции .init3, т.е. после инициализации внутренних регистров и стека, но до очистки статических переменных... вот тогда время будет минимальным. хотя, имхо, и так страху нет

Re: Нескольно простых вопросов о программировании AVR на Си.

Пн июл 17, 2023 11:47:11

но сброситься может и не от только от внутреннего ватчдога же, может, внешний сбросил

Добавлено after 3 minutes 19 seconds:
хотя, имхо, и так страху нет
согласен.

Re: Нескольно простых вопросов о программировании AVR на Си.

Ср июл 19, 2023 07:51:14

Вопрос знатокам, есть две восьмибитных переменных А и В
Как просто младший полубайт переменной А сохранить (перенести) в младший полубайт переменной В, не изменяя значение старшего полубайта переменной В?
Ответить