
Нескольно простых вопросов о программировании AVR на Си.
-
Pnjom-Penb
- Мучитель микросхем
- Сообщения: 469
- Зарегистрирован: Вс авг 30, 2015 03:52:59
Re: Нескольно простых вопросов о программировании AVR на Си.
В двух предыдущих постах, рассуждения об атомарности - оторваны от рассматриваемой ситуации. То есть - мимо кассы. 

- DronVolk
- Встал на лапы
- Сообщения: 109
- Зарегистрирован: Чт сен 03, 2015 15:52:10
- Откуда: Сибирский федеральный округ
Re: Нескольно простых вопросов о программировании AVR на Си.
Почему? я говорил о том что если писать в регистры как обычно и так придется использовать несколько инструкций (записать значение бита в один регистр и во второй это минимум 2 инструкции) для одной настройки. А битовые поля сами по себе не атомарны запись: [перейти по указателю-> считать исходное значение-> применить логическое или с новым значением -> записать обратно] (само значение бита(ов) двигать еще придется) чтение [перейти по указателю-> считать значение -> применить маску] (возможно ее тоже считать во время исполнения придется).
я повелитель электронов! Но иногда появляются электроны бунтари и делают, что им вздумается, например, прокладывают новые пути движения...
"Только те, кто предпринимают абсурдные попытки, смогут достичь невозможного." Альберт Эйнштейн.
"Только те, кто предпринимают абсурдные попытки, смогут достичь невозможного." Альберт Эйнштейн.
- COKPOWEHEU
- Говорящий с текстолитом
- Сообщения: 1525
- Зарегистрирован: Чт июн 10, 2010 20:11:19
Re: Нескольно простых вопросов о программировании AVR на Си.
DronVolk писал(а):не бред! Любые манипуляции с регистрами желательно защищать если нет уверенности в атоморности и тут нужно смотреть высер компилятора
Обычно эти настройки выполняются в начале программы, когда прерывания запрещены. То есть просто обернуть их парой cli/sei нельзя (а то прерывания будут разрешены слишком рано). Можно, конечно, сохранить весь SREG, но это все равно минимум 2 лишние команды.
А какую ситуацию вы рассматриваете? Лично я - общую, для нее пример и дал.Pnjom-Penb писал(а):В двух предыдущих постах, рассуждения об атомарности - оторваны от рассматриваемой ситуации. То есть - мимо кассы.
Кстати, я не в курсе, гарантируется ли постоянство адресов. То есть если в ATmega8 регистры TCCR1A и TCCR1B расположены по адресам 0x2F и 0x2E, будут ли они во всех контроллерах идти последовательно и в том же порядке? Это представляется логичным, но гарантируется ли где-нибудь?
Ну и запись значений напрямую в регистры выглядит компактнее и проще, чем нагромождение настроек отдельных битов. Даже не повторяя про умение avr-gcc работать с битовыми полями.
Может, проще через макросы? Что-то вроде
Код: Выделить всё
TIMER_SET_MODE(1,TIMER_PWM);
TIMER_SET_PRESCALER(0, TIMER_128);
Если использовать именно указатель - да, по скорости, объему и, частично, надежности все будет печально. А вот изменение 1-2 битов в регистре это 1-2 команды sbr/cbr. Положить битовую структуру на константный адрес может быть непросто (скорее по внешнему виду).А битовые поля сами по себе не атомарны
-
Pnjom-Penb
- Мучитель микросхем
- Сообщения: 469
- Зарегистрирован: Вс авг 30, 2015 03:52:59
Re: Нескольно простых вопросов о программировании AVR на Си.
Честно говоря, мне сейчас не по-джентльменски отвлекаться на всякие мелочи и оставлять даму без внимания.DronVolk писал(а):Почему?
Выше уже достаточно сказано, чтобы все отловить. Кстати - в статье, по второй ссылке, предоставленной Вами же, все уже сказано. Вы только ищете статьи, но не читаете их?
- DronVolk
- Встал на лапы
- Сообщения: 109
- Зарегистрирован: Чт сен 03, 2015 15:52:10
- Откуда: Сибирский федеральный округ
Re: Нескольно простых вопросов о программировании AVR на Си.
COKPOWEHEU писал(а):Может, проще через макросы? Что-то вродеКод: Выделить всё
TIMER_SET_MODE(1,TIMER_PWM);
TIMER_SET_PRESCALER(0, TIMER_128);
Причем, поскольку менять режим работы таймера "на лету" вряд ли понадобится, можно обойтись без атомарности, при необходимости реализовав ее снаружи.
вопрос изначально полез не в ту сторону
Код: Выделить всё
Timer_setup(0)
Com_A_Disable()
Com_B_Set()
Prescale_x8()
...
End_Timer_Setup()
это разворачивалось уже в запись в регистры, но проблемы были в том, что макросы иногда уезжали и на выходе получалось не то. (сами макросы получались больше чем если бы битовые поля использовать вот и задумался)
Каждый сам решит через призму своего опыта и заблуждений что лучше для него самого.
я повелитель электронов! Но иногда появляются электроны бунтари и делают, что им вздумается, например, прокладывают новые пути движения...
"Только те, кто предпринимают абсурдные попытки, смогут достичь невозможного." Альберт Эйнштейн.
"Только те, кто предпринимают абсурдные попытки, смогут достичь невозможного." Альберт Эйнштейн.
- c2n
- Сверлит текстолит когтями
- Сообщения: 1193
- Зарегистрирован: Ср июл 25, 2012 21:40:09
- Откуда: Самара
- Контактная информация:
Re: Нескольно простых вопросов о программировании AVR на Си.
Комрады! наткнулся на грабли. АВР студия 5 и выше. Микроконтроллер 8535 и атмега16.
При попытке выполнить следующий код:
unsigned long uValue = 0;
uValue |= (1<<15);
uValue принимает значение 0xFF FF 80 00
хотя я ожидаю 0x00 00 80 00
код: uValue |= (0b1000000000000000); такое безобразие не делает.
подскажите - WTF ???
При попытке выполнить следующий код:
unsigned long uValue = 0;
uValue |= (1<<15);
uValue принимает значение 0xFF FF 80 00
хотя я ожидаю 0x00 00 80 00
код: uValue |= (0b1000000000000000); такое безобразие не делает.
подскажите - WTF ???
- WiseLord
- Друг Кота
- Сообщения: 4905
- Зарегистрирован: Чт апр 11, 2013 11:19:59
- Откуда: Минск
- Контактная информация:
Re: Нескольно простых вопросов о программировании AVR на Си.
Всё верно.
1) Числа 1 и 15 - это signed int,
2) (1<<15) даёт 0x8000 - отрицательное 16-битное число (signed int), оно же равно -32768.
3) Приведение его к 32-битному даёт 0xFFFF8000, оно же -32768
1) Числа 1 и 15 - это signed int,
2) (1<<15) даёт 0x8000 - отрицательное 16-битное число (signed int), оно же равно -32768.
3) Приведение его к 32-битному даёт 0xFFFF8000, оно же -32768
- c2n
- Сверлит текстолит когтями
- Сообщения: 1193
- Зарегистрирован: Ср июл 25, 2012 21:40:09
- Откуда: Самара
- Контактная информация:
Re: Нескольно простых вопросов о программировании AVR на Си.
Да. Разобрался. Спасибо!
По умолчанию компилятор студии воспринимает все не явно объявленные значения как signed int.
Для борьбы с подобного рода неясностями необходимо числа объявлять явно.
Конструкция
uValue |= (1UL<<15);
дает ожидаемый результат
По умолчанию компилятор студии воспринимает все не явно объявленные значения как signed int.
Для борьбы с подобного рода неясностями необходимо числа объявлять явно.
Конструкция
uValue |= (1UL<<15);
дает ожидаемый результат
- ARV
- Ум, честь и совесть. И скромность.
- Сообщения: 18544
- Зарегистрирован: Чт дек 28, 2006 08:19:56
- Откуда: Новочеркасск
- Контактная информация:
Re: Нескольно простых вопросов о программировании AVR на Си.
вообще-то любой вменяемый компилятор Си так поступает. причем не как signed int, а как просто int (signed int это масло масляное)c2n писал(а):По умолчанию компилятор студии воспринимает все не явно объявленные значения как signed int.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
- Balzercvua
- Потрогал лапой паяльник
- Сообщения: 311
- Зарегистрирован: Вт дек 31, 2013 17:36:43
Re: Нескольно простых вопросов о программировании AVR на Си.
Добрый Вечер Коты!!!
У меня есть один вопрос точнее прошение обьясните что конкретно делает конткретный фрагмент кода!!!Я программирую в баском с Си практически не знаком
{
CB(PORT_LCD,CS);
if(com==0)
CB(PORT_LCD,RS);
else
SB(PORT_LCD,RS);
SB(PORT_LCD,SCK);
for(unsigned char i=0;i<8;i++)
{
if(((c>>(7-i))&1) == 1)
SB(PORT_LCD,MOSI);
else
CB(PORT_LCD,MOSI);
CB(PORT_LCD,SCK);
SB(PORT_LCD,SCK);
}
SB(PORT_LCD,CS);
}
У меня есть один вопрос точнее прошение обьясните что конкретно делает конткретный фрагмент кода!!!Я программирую в баском с Си практически не знаком
Спойлер
void write_byte(unsigned char c,unsigned char com)//0-command 1-data{
CB(PORT_LCD,CS);
if(com==0)
CB(PORT_LCD,RS);
else
SB(PORT_LCD,RS);
SB(PORT_LCD,SCK);
for(unsigned char i=0;i<8;i++)
{
if(((c>>(7-i))&1) == 1)
SB(PORT_LCD,MOSI);
else
CB(PORT_LCD,MOSI);
CB(PORT_LCD,SCK);
SB(PORT_LCD,SCK);
}
SB(PORT_LCD,CS);
}
- WiseLord
- Друг Кота
- Сообщения: 4905
- Зарегистрирован: Чт апр 11, 2013 11:19:59
- Откуда: Минск
- Контактная информация:
Re: Нескольно простых вопросов о программировании AVR на Си.
Реализация SPI. Достаточно кривая, но вроде как рабочая.
- Balzercvua
- Потрогал лапой паяльник
- Сообщения: 311
- Зарегистрирован: Вт дек 31, 2013 17:36:43
Re: Нескольно простых вопросов о программировании AVR на Си.
WiseLord писал(а):Реализация SPI. Достаточно кривая, но вроде как рабочая.
Я попросил обьяснить что он делает а не что это такое я не могу понять сами циклы и условия обьясните пожайлуста если не трудно
Re: Нескольно простых вопросов о программировании AVR на Си.
Телепатирую...
IMHO, т.е.
CB и SB скорее всего макросы принимающие два параметра - порт и номер бита.
CB - clear bit, очистить, сбросить бит в "0"
SB - set bit, установить в "1"
PORT_LCD, RS, MOSI, MISO и т.д. определённые с помощью #define метки указывающие на реальные порт и биты.
Если ты представляешь что такое SPI, то дальше вопросов быть не должно.
Выбор устройства, устанавливается бит команда или данные и строб.
Далее цикл отправки 8 бит.
В if-е проверка i-того бита...
Строб.
После цикла "отпустить" устройство.
Если надо более детально, то сужай область непонятного.
Если не видел ещё, полезно бывает.
CB и SB скорее всего макросы принимающие два параметра - порт и номер бита.
CB - clear bit, очистить, сбросить бит в "0"
SB - set bit, установить в "1"
PORT_LCD, RS, MOSI, MISO и т.д. определённые с помощью #define метки указывающие на реальные порт и биты.
Если ты представляешь что такое SPI, то дальше вопросов быть не должно.
Выбор устройства, устанавливается бит команда или данные и строб.
Код: Выделить всё
CB(PORT_LCD,CS);
if(com==0)
CB(PORT_LCD,RS);
else
SB(PORT_LCD,RS);
SB(PORT_LCD,SCK);Далее цикл отправки 8 бит.
В if-е проверка i-того бита...
Строб.
После цикла "отпустить" устройство.
Код: Выделить всё
for(unsigned char i=0;i<8;i++)
{
if(((c>>(7-i))&1) == 1)
SB(PORT_LCD,MOSI);
else
CB(PORT_LCD,MOSI);
CB(PORT_LCD,SCK);
SB(PORT_LCD,SCK);
}
SB(PORT_LCD,CS);
Если надо более детально, то сужай область непонятного.
Если не видел ещё, полезно бывает.
Когда уже ничего не помогает - прочтите, наконец, инструкцию.
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
- Balzercvua
- Потрогал лапой паяльник
- Сообщения: 311
- Зарегистрирован: Вт дек 31, 2013 17:36:43
Re: Нескольно простых вопросов о программировании AVR на Си.
Kavka писал(а):Телепатирую...
Спойлер
void WriteTwoByte(unsigned char LCD_DataH,unsigned char LCD_DataL){
write_byte(LCD_DataH,1);
write_byte(LCD_DataL,1);
}
void OutColor(unsigned int color)
{
WriteTwoByte((color>>8),((color<<8)>>8));
}
Обьясни пожалуйста операции со сдвигом битов первое я понял что они здвигаютса в право на 8 а вот второй кусок для меня непонятен
- COKPOWEHEU
- Говорящий с текстолитом
- Сообщения: 1525
- Зарегистрирован: Чт июн 10, 2010 20:11:19
Re: Нескольно простых вопросов о программировании AVR на Си.
Kavka писал(а):Код: Выделить всё
if(((c>>(7-i))&1) == 1)
Вот так делать не стоит - слишком медленно. Лучше скопировать в локальную переменную, а ее сдвигать не боясь
char temp - c;
Код: Выделить всё
for(i=0;i<8;i++){
if( temp & (1<<7))
SB(PORT_LCD,MOSI);
else
CB(PORT_LCD,MOSI);
temp <<=1;
CB(PORT_LCD,SCK);
SB(PORT_LCD,SCK);
}
SB(PORT_LCD,CS);Код: Выделить всё
char temp=(1<<7);
for(i=0;i<8;i++){
if( c & temp)
SB(PORT_LCD,MOSI);
else
CB(PORT_LCD,MOSI);
temp >>=1;
...Код: Выделить всё
const char mask[8]={(1<<7), (1<<6), (1<<5), (1<<4), (1<<4), (1<<3), (1<<2), (1<<1), (1<<0)};
for(i=0;i<8;i++){
if( c & mask[i])
...Обьясни пожалуйста операции со сдвигом битов первое я понял что они здвигаютса в право на 8 а вот второй кусок для меня непонятен
Первое - да, сдвиг вправо на 8 бит, то есть старший байт числа, второе - шаманство, не очень понятно что и зачем делается, если можно обойтись простым приведением типа.
WriteTwoByte((unsigned char)(color>>8),(unsigned char)color);
Если я правильно помню, стандартом не оговариваются ни размер, ни наличие знака у стандартных типов, это сделано для упрощения разработки компиляторов. То есть int может быть эквивалентен int32_t, uint16_t и другим, и это нормально.причем не как signed int, а как просто int (signed int это масло масляное)
- ARV
- Ум, честь и совесть. И скромность.
- Сообщения: 18544
- Зарегистрирован: Чт дек 28, 2006 08:19:56
- Откуда: Новочеркасск
- Контактная информация:
Re: Нескольно простых вопросов о программировании AVR на Си.
нет, int всегда знаковый.COKPOWEHEU писал(а):Если я правильно помню, стандартом не оговариваются ни размер, ни наличие знака у стандартных типов, это сделано для упрощения разработки компиляторов. То есть int может быть эквивалентен int32_t, uint16_t и другим, и это нормально.
COKPOWEHEU писал(а):Или даже так
Код: Выделить всё
char temp=(1<<7);
for(; temp; temp >>= 1){
if( c & temp)
SB(PORT_LCD,MOSI);
else
CB(PORT_LCD,MOSI);
...если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
Re: Нескольно простых вопросов о программировании AVR на Си.
Balzercvua писал(а):Код: Выделить всё
void OutColor(unsigned int color)
{
WriteTwoByte((color>>8),((color<<8)>>8));
}
unsigned int тут это 16-битное целое (например тынц).
Соответственно задвинув его влево на 8 бит теряются старшие 8 бит. И сдвинув обратно получаем нули в старших битах.
Проще или сделать приведение типов (как уже упоминалось) или побитовое "И" с маской из 8-ми бит.
Когда уже ничего не помогает - прочтите, наконец, инструкцию.
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
Re: Нескольно простых вопросов о программировании AVR на Си.
Здравствуйте всем.
Только начал изучать программирование AVR. Решил начать с Си. Поставил AVRStudio 5.0. И AtTiny13. Написал программку включения диода:
#include <avr/io.h>
#include <avr/interrupt.h> // Подключение системного файла для работы с прерываниями
//SIGNAL(INT0_vect)
SIGNAL(SIG_INTERRUPT0) // Обработчик прерываний
{
PORTB ^= 0x01;
}
int main(void)
{
PORTB = 0b11111111;
DDRB = 0b00000001;
GIMSK = 0b01000000; // Разрешение прерываний INT0 на входе PB1
MCUCR = 0b00000010; // при перепаде из 1 в 0
sei(); // Общее разрешение прерываний
while (1) {}
}
Получил .hex фаил 1кБайт. Предел, но можно
Добавляю задержку
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
//SIGNAL(INT0_vect)
SIGNAL(SIG_INTERRUPT0)
{
_delay_ms(200); // Задержка 200 миллисекунд
if (bit_is_clear(PINB,PB1)) // Опрос PB1
PORTB ^= 0x01;
}
int main(void)
{
PORTB = 0b11111111;
DDRB = 0b00000001;
GIMSK = 0b01000000; // Разрешение прерываний INT0 на входе PB1
MCUCR = 0b00000010; // при перепаде из 1 в 0
sei();
while (1) {}
}
И плучаю .hex объемом 6 кбайт.
Может я чего не понимаю?
У AtTiny13 flash 1 кБайт.
Помогите понять, пожалуйста, я с дуба рухнул вниз башкой, или 5-я AVRStudio ?
Только начал изучать программирование AVR. Решил начать с Си. Поставил AVRStudio 5.0. И AtTiny13. Написал программку включения диода:
#include <avr/io.h>
#include <avr/interrupt.h> // Подключение системного файла для работы с прерываниями
//SIGNAL(INT0_vect)
SIGNAL(SIG_INTERRUPT0) // Обработчик прерываний
{
PORTB ^= 0x01;
}
int main(void)
{
PORTB = 0b11111111;
DDRB = 0b00000001;
GIMSK = 0b01000000; // Разрешение прерываний INT0 на входе PB1
MCUCR = 0b00000010; // при перепаде из 1 в 0
sei(); // Общее разрешение прерываний
while (1) {}
}
Получил .hex фаил 1кБайт. Предел, но можно
Добавляю задержку
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
//SIGNAL(INT0_vect)
SIGNAL(SIG_INTERRUPT0)
{
_delay_ms(200); // Задержка 200 миллисекунд
if (bit_is_clear(PINB,PB1)) // Опрос PB1
PORTB ^= 0x01;
}
int main(void)
{
PORTB = 0b11111111;
DDRB = 0b00000001;
GIMSK = 0b01000000; // Разрешение прерываний INT0 на входе PB1
MCUCR = 0b00000010; // при перепаде из 1 в 0
sei();
while (1) {}
}
И плучаю .hex объемом 6 кбайт.
Может я чего не понимаю?
У AtTiny13 flash 1 кБайт.
Помогите понять, пожалуйста, я с дуба рухнул вниз башкой, или 5-я AVRStudio ?
- oleg110592
- Друг Кота
- Сообщения: 3832
- Зарегистрирован: Сб сен 10, 2011 17:46:25
Re: Нескольно простых вопросов о программировании AVR на Си.
.hex это текстовый файл, его размер не отражает объем занимаемого flash
https://ru.wikipedia.org/wiki/Intel_HEX
https://ru.wikipedia.org/wiki/Intel_HEX
- WiseLord
- Друг Кота
- Сообщения: 4905
- Зарегистрирован: Чт апр 11, 2013 11:19:59
- Откуда: Минск
- Контактная информация:
Re: Нескольно простых вопросов о программировании AVR на Си.
а) Первое компилируется в 94 байта (hex 279 байт), второе - в 120 байт (hex 357 байт). Это при уровне оптимизации -Os.
б) SIGNAL(SIG_INTERRUPT0) - устарело и новые компиляторы на это ругаются (poisoned interrupt). Лучше использовать ISR(INT0_vect).
в) Код странноват. Да, он рабочий - в рамках техзадания - и установка бита 0 в лог. 1 перед выходом из прерывания приведёт к новому прерыванию сразу после выхода. Но боюсь, на основной цикл, будь там что-то посерьёзнее while() {}, процессора уже не хватит.
г) Ну и классика - задержка (тем более такая большая) в прерывании - зло. Хотя в рамках изучения прерываний сойдёт.
б) SIGNAL(SIG_INTERRUPT0) - устарело и новые компиляторы на это ругаются (poisoned interrupt). Лучше использовать ISR(INT0_vect).
в) Код странноват. Да, он рабочий - в рамках техзадания - и установка бита 0 в лог. 1 перед выходом из прерывания приведёт к новому прерыванию сразу после выхода. Но боюсь, на основной цикл, будь там что-то посерьёзнее while() {}, процессора уже не хватит.
г) Ну и классика - задержка (тем более такая большая) в прерывании - зло. Хотя в рамках изучения прерываний сойдёт.