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

Обсуждаем контроллеры компании Atmel.
Ответить
Грызет канифоль
Аватара пользователя
Сообщения: 275
Зарегистрирован: Вс окт 20, 2019 13:03:56

Сообщение Shuspano »

Добрый день. Попалась вот такая запись в операции установки бит.

Код: Выделить всё

 UCSR0C=(3<<UCSZ00); 
Почему здесь тройка, и что она значит. Сколько ни смотрел разные руководства по битовым операциям, везде тут единица без исключений.
Компилируется и работает нормально.
Реклама
Поставщик валерьянки для Кота
Сообщения: 1986
Зарегистрирован: Сб май 05, 2012 20:24:52
Откуда: KN34PC, Болгария

Сообщение veso74 »

Устанавливают 2 бита сразу.
Замените частях, в какой системе счисления хотите, напр. в двоичном.
3 -> 0b00000011
UCSZ00 (atmega328?, стр. 193) -> 1

UCSR0C = (3 << UCSZ00);
UCSR0C = (0b00000011 << 1);
UCSR0C = 0b00000110;

Смотрим документацию (стр. 193, 194):
The UCSZn1:0 bits combined with the UCSZn2 bit in UCSRnB sets the number of data bits (Character SiZe) in a frame the Receiver and Transmitter use.
(UCSZn2 = 0?), UCSZn1 = 1, UCSZn0 = 1 -> Character Size: 8-bit
Контактная информация:
Реклама
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18794
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

[uquote="Shuspano",url="/forum/viewtopic.php?p=4425543#p4425543"]Добрый день. Попалась вот такая запись в операции установки бит.

Код: Выделить всё

 UCSR0C=(3<<UCSZ00); 
Почему здесь тройка, и что она значит. Сколько ни смотрел разные руководства по битовым операциям, везде тут единица без исключений.
Компилируется и работает нормально.[/uquote]
нормальные люди делают так:

Код: Выделить всё

UCSR0C=_BV(UСSZ00) | _BV(UCSZ01);
или так (что то же самое, но длиннее):

Код: Выделить всё

UCSR0C=(1<<UСSZ00) | (1<<UCSZ01);
, а ненормальные двигают сразу 2 бита в позицию UCSZ00, как у вас
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
Поставщик валерьянки для Кота
Сообщения: 1986
Зарегистрирован: Сб май 05, 2012 20:24:52
Откуда: KN34PC, Болгария

Сообщение veso74 »

Тоже нормальные люди это те, кто также написали документацию ATmega48A/PA/88A/PA/168A/PA/328/P :).

стр. 185, Assembly Code Example:

Код: Выделить всё

USART_Init:
; Set baud rate
out UBRRnH, r17
out UBRRnL, r16
; Enable receiver and transmitter
ldi r16, (1<<RXENn)|(1<<TXENn)
out UCSRnB,r16
; Set frame format: 8data, 2stop bit
ldi r16, (1<<USBSn)|(3<<UCSZn0)
out UCSRnC,r16
ret
стр. 185, C Code Example:

Код: Выделить всё

Enable receiver and transmitter */
UCSR0B = (1<<RXEN0)|(1<<TXEN0);
/* Set frame format: 8data, 2stop bit */
UCSR0C = (1<<USBS0)|(3<<UCSZ00);
Контактная информация:
Реклама
Эиком - электронные компоненты и радиодетали
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18794
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

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

Мой уютный бложик... заходите!
Контактная информация:
Реклама
OKF
Это не хвост, это антенна
Сообщения: 1456
Зарегистрирован: Вт июн 07, 2011 08:03:18

Сообщение OKF »

[uquote="Martian",url="/forum/viewtopic.php?p=4425966#p4425966"]Лично я за удобочитаемость...[/uquote] Стараюсь указывать все используемые биты, типа, REG = 1<<bit1 | 0<<bit0; и тогда явно видно какие биты в каком состоянии.
Реклама
Грызет канифоль
Аватара пользователя
Сообщения: 275
Зарегистрирован: Вс окт 20, 2019 13:03:56

Сообщение Shuspano »

А зачем такие сложности? Почему нельзя просто UCSR0C = 0x06;
Там же нет битов, которые меняются в процессе работы, и которые можно испортить. Я как понял, это никакая не битовая операция, а как записать байт в регистр идиотским способом.
Поставщик валерьянки для Кота
Сообщения: 1986
Зарегистрирован: Сб май 05, 2012 20:24:52
Откуда: KN34PC, Болгария

Сообщение veso74 »

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

Пример из TinyI2C:

Код: Выделить всё

USICR = 0<<USISIE | 0<<USIOIE | 1<<USIWM1 | 0<<USIWM0 | 1<<USICS1 | 0<<USICS0 | 1<<USICLK | 0<<USITC;
Контактная информация:
OKF
Это не хвост, это антенна
Сообщения: 1456
Зарегистрирован: Вт июн 07, 2011 08:03:18

Сообщение OKF »

Плюс. Перед глазами все биты USICR, которые можно изменить одним движением, при необходимости.
Друг Кота
Аватара пользователя
Сообщения: 7083
Зарегистрирован: Пт ноя 11, 2016 05:48:09
Откуда: Сердце Пармы

Сообщение Ivanoff-iv »

я делаю как ненормальные... но указываю все биты в т.ч. и 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 КБ) 412 скачиваний
Для тех, кто не учил магию мир полон физики :)
Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
Поставщик валерьянки для Кота
Сообщения: 1986
Зарегистрирован: Сб май 05, 2012 20:24:52
Откуда: KN34PC, Болгария

Сообщение veso74 »

В последних выражениях много тавтологии - не упрощаем пользователю, а усложняем :P.

Код: Выделить всё

TCCR1B=(_ICNC1<<ICNC1) | (_ICES1<<ICES1) | ((_WGM1>>2)<<WGM12) | (_CS1<<CS10);
...
#ifdef _WGM1
  | ((WGM1>>2)<<WGM12)
#endif
Если бы у меня был выбор редактировать, я бы пропустил код даже для понимания :).
А если придется: следует полная замена/переписывание.
Контактная информация:
Друг Кота
Аватара пользователя
Сообщения: 7083
Зарегистрирован: Пт ноя 11, 2016 05:48:09
Откуда: Сердце Пармы

Сообщение Ivanoff-iv »

нет, этот код пользователь не увидит, для него настройка будет выглядеть так:
Спойлер

Код: Выделить всё

// 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:
Для тех, кто не учил магию мир полон физики :)
Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
Встал на лапы
Сообщения: 121
Зарегистрирован: Пт мар 19, 2021 08:58:45

Сообщение kote52 »

Всем привет! Собрал я для своей дачи контроллер для озонирования воды, т.к. в воде много двухвалентного железа, его как то надо окислять, чтобы применять воду для бытовых нужд, озон лучше всего для этого подходит еще попутно очень хорошо обеззараживает воду. Вся система состоит из двух бочек, алгоритм таков: первую бочку скважный насос накачивает воду, после наполнения бочки включается циркуляционный насос и гоняет воду по кругу в первой бочке через эжектор Вентури, тем самым смешивает воду с озоном из озонатора 1 час(по таймеру), далее отстаивание воды 6 часов(по таймеру), далее перелив воды через электромагнитный клапан во вторую расходную бочку, откуда после наполения второй бочки третий насос с гидроаккамулятром подает воду в дом на разбор. Всем этим действием и управляет контроллер на atmega8. Решил прикрутить еще "собаку", ну мало ли завис, сбросит. Но тут же возникает вопрос из за незнания применения "собаки", к примеру зависло во время одного из действия когда считает таймер, "собака" сбросила, т.е. все сначало, весь счет таймера потерялся... как с этим быть, писать в энергонезависимую память раз в секунду/минуту какая часть программы выполнялась, счет таймера, ресурс быстро израсходую? писать все тоже самое отдельную память?
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18794
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

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

Мой уютный бложик... заходите!
Контактная информация:
Встал на лапы
Сообщения: 121
Зарегистрирован: Пт мар 19, 2021 08:58:45

Сообщение kote52 »

[uquote="ARV",url="/forum/viewtopic.php?p=4444882#p4444882"]считать таймер в переменных, не очищаемых при сбросе МК[/uquote]
это каких? static?
Поставщик валерьянки для Кота
Сообщения: 1986
Зарегистрирован: Сб май 05, 2012 20:24:52
Откуда: KN34PC, Болгария

Сообщение veso74 »

Код: Выделить всё

uint8_t count __attribute__ ((section (".noinit")));
Контактная информация:
Встал на лапы
Сообщения: 121
Зарегистрирован: Пт мар 19, 2021 08:58:45

Сообщение kote52 »

[uquote="veso74",url="/forum/viewtopic.php?p=4444941#p4444941"]

Код: Выделить всё

uint8_t count __attribute__ ((section (".noinit")));
[/uquote]
Спсибо, пойду подтягивать теорию! :beer:
Мучитель микросхем
Сообщения: 437
Зарегистрирован: Пн май 27, 2019 07:18:28
Откуда: ВВХ-ск

Сообщение mont-oriol »

[uquote="kote52",url="/forum/viewtopic.php?p=4444850#p4444850"]к примеру зависло во время одного из действия когда считает таймер, "собака" сбросила, т.е. все сначало, весь счет таймера потерялся... как с этим быть, писать в энергонезависимую память раз в секунду/минуту какая часть программы выполнялась, счет таймера, ресурс быстро израсходую? писать все тоже самое отдельную память?[/uquote]
В самом дешёвом модуле RTC для ардуинки, в чипе DS1307 есть ещё и SRAM с питанием от батареи, 56 байт. Можно туда заливать текущее состояние, дублируя трижды, с учётом того, что МК может зависнуть во время записи. А при старте сравнивать все три сохранённых блока, если два идущих подряд совпали - можно их использовать для восстановления состояния.
Либо просто использовать время из RTC, типа "если сейчас от 01 до 06 часов утра - гонять воду в первом баке".
Встал на лапы
Сообщения: 121
Зарегистрирован: Пт мар 19, 2021 08:58:45

Сообщение kote52 »

[uquote="veso74",url="/forum/viewtopic.php?p=4444941#p4444941"]

Код: Выделить всё

uint8_t count __attribute__ ((section (".noinit")));
[/uquote]
и
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);  //выкл насос
	}
    }
}
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18794
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

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

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

Мой уютный бложик... заходите!
Контактная информация:
Ответить

Вернуться в «AVR»