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

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

Ср мар 04, 2015 12:32:33

Вот это немного не ясно, получается во всех разрядах в скобках стоят нули, затем в номер бита пишем 1, все инвертируем. Там где наш нужный номер бита стал нулем логическое И даст ноль в регистре, а ост. разряды не изменит? Где-то так?

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

Ср мар 04, 2015 12:37:58

LED_PORT = LED_PORT & (0<<LED2);
Получается тут обн. Весь порт?

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

Ср мар 04, 2015 12:43:53

Compressor писал(а):LED_PORT = LED_PORT & (0<<LED2);
Получается тут обн. Весь порт?

эта операция, ее можно записать проще PORT & = (0<<bit) выполняет не что иное как логическое И над портом
а эта PORT & =~ (0<<bit) делает сброс нужного вам бита в порте, в данном случае нулевого
Последний раз редактировалось FreshMan Ср мар 04, 2015 12:48:32, всего редактировалось 1 раз.

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

Ср мар 04, 2015 12:48:32

Я понял, спасибо.

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

Чт мар 05, 2015 09:17:08

Добрый день!
Заинтересовал меня один вопрос, на ЖК я хочу вывести символ 0xA5
Код:
lcd_putchar(0xA5);

появляется буква И, как и положено. Дальше хочу вывести ±, мне нужно написать 0x90? (так ничего не получается).

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

Чт мар 05, 2015 09:48:16

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

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

Чт мар 05, 2015 09:53:40

Думаю, Вам придется самостоятельно генерировать символ ± в CGRAM.

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

Чт мар 05, 2015 10:00:06

Это я в протеусе все пробовал.

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

Чт мар 05, 2015 10:02:06

Попробуйте загрузить 0xB1. Может повезёт.

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

Чт мар 05, 2015 10:37:29

akl писал(а):Попробуйте загрузить 0xB1. Может повезёт.

Выводит букву Я.

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

Чт мар 05, 2015 14:38:06

FreshMan писал(а):эта операция, ее можно записать проще PORT & = (0<<bit) выполняет не что иное как логическое И над портом
а эта PORT & =~ (0<<bit) делает сброс нужного вам бита в порте, в данном случае нулевого
В корне неверно. Первая операция обнуляет весь порт, а вторая операция не делает ничего вообще. Не учите неправильным и неработающим вещам.

Правильное использование (допустим, bit = 3):

Установка бита:
PORT |= (1<<bit) равносильно PORT = PORT | (1<<bit) равносильно PORT = PORT | 00001000

Сброс бита:
PORT &= ~(1<<bit) равносильно PORT = PORT & ~(1<<bit) равносильно PORT = PORT & 11110111

Всё остальное - от лукавого. (0<<bit) вообще не имеет смысла, так как всегда равно нулю и не зависит от bit.
Compressor писал(а):LED_PORT = LED_PORT & (0<<LED2);
Получается тут обн. Весь порт?
Именно так. Порт логически умножается на ноль.

kk042fjv писал(а):Это я в протеусе все пробовал.
Насколько я понял, Вы русские буквы в протеусе видите. Значит, вероятнее всего, подменили библиотеку тамошнюю на русифицированную.

А у этой русифицированной библиотеки глюки с работой знакогенератора. По крайней мере, у меня знакогенератор в ней не работает, в отличие от оригинальной (которая, увы, без кириллицы).

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

Чт мар 05, 2015 19:46:31

Здравствуйте, дабы не плодить темы, тем более тут разговор довольно близкий к моим вопросам.
Я только только знакомлюсь и с AVR и с Си. Прочитал пару тройку статей на тему программирования МК, и даже собрал небольшой тестовый стендик на ATmega8.

В качестве практики появилась идея написать программу для упревления доп освещением в машине.
Итак:
есть 4 группы лампочек и 3 кнопки
1 кнопка управляет по определенному алгоритму первой группой. (нажал кнопку горит отпустил потухла, нажал и держишь 2 секунды включается на постоянку, и отключается только при следующем нажатии)
2 кнопка точно по такому же алгоритму управляет второй группой.
3 кнопка попеременно а затем вместе включает оставшиеся группы.

Первый и самый главный вопрос: как рулить отдельно каждым пином если все пины находятся на одном порту? а то как не думал, не получается :)
2 через какую функцию лучше всего реализовывать алгоритм? пробовал через delay не удобно, я так понял при команде delay останавливается вся программа. пробовал через прерывания, тоже ничего путного не получилось )))

В общем у меня ничего не получается, поможите советом пожалуйста.

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

Чт мар 05, 2015 20:36:43

DrRain писал(а):как рулить отдельно каждым пином если все пины находятся на одном порту?
самым тривиальным способом: http://arv.radioliga.com/content/category/6/33/49/ - первые два пункта FAQ

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

Чт мар 05, 2015 21:31:31

WiseLord писал(а):вторая операция не делает ничего вообще.

извиняюсь, нолик не заметил :)

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

Пт мар 06, 2015 18:34:02

Благодарю, вроде разобрался, может быть еще подскажете как реализовать функционал (поморгать лампочкой при помощи кнопки, а если кнопку подержать пару секунд, то лампочка включится на постоянку)?

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

Пт мар 06, 2015 20:01:30

Завести счётчик, наращиваемый, например, раз в миллисекунду (по таймеру). Считать только при нажатой кнопке.

Завести переменную-флаг постоянного горения, изначально сброшенный.

При нажатии кнопки, если флаг сброшен, включить лампочку и начать счёт. Если же флаг установлен - выключить счёт, сбросить флаг и сбросить счётчик. При отпускании кнопки, если счёт не достиг 2000, погасить лампочку и сбросить счёт. Если же достиг - оставить зажжённой и установить флаг.

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

Сб мар 07, 2015 09:13:05

попробовал написать по Вашему алгоритму, вроде как так :)
пока не могу въехать в тонкости счетчиков. в общем ничего у меня не заработало ))))
Код:
#include <avr/io.h>
#include <avr/interrupt.h>
 
unsigned char cou1;  // назначаем переменную
char Flag1=0; // переменная флаг изначально сброшенный.

 
ISR (TIMER1_OVF_vect)
{
   if ((PIND&(1 << PD0)) == 0) // если кнопка PD0 нажата
   {
      if(Flag1==0)
      {
         PORTB=0b00000001; //включить ламочку
         cou1 = cou1+1; // пока кнопка нажата добавляем +1 в перем нную каждый цикл
      }
      else // если флаг не равен 0
      {
         cou1=0; //сбросим счетчик
         Flag1=0; // сбросим флаг
      }
      
   }
   if ((PIND&(1 << PD0)) == 1) // если кнопка отпущена
   {
      if(cou1<2000) // еслисчетчик не достиг значение
      {
         PORTB=0b00000000; //выключим лампочку
         cou1=0;            //сбросим счетчик
      }
      else // если достиг
      {
         PORTB=0b00000001; //включаем лампочку
         Flag1=1;      //устанавливаем флаг
      }
   }
}
   
 
int main(void)
{
 
DDRB= 0b11111111; //определяем PORTB на выход
PORTB= 0x00;   // изначально все лампочки на порту B выключены

DDRD = 0b11111000; //устанавливаем первые три ножки на вход остальные на выход
PORTD= 0b00000111; //подключаем к первым трем ножкам подт резисторы остальные уст в 0
 
TCCR1B = (1 << CS12)|(0 << CS11)|(1 << CS10)|(1 << WGM12); //предделитель clk/1024, режим таймера СТС
TCNT1 = 0;
TIMSK |= (1<<TOIE1); // разрешаем прерывание по переполнению таймера
cou1 = 0; // Присвоение начального значения
 
sei(); // Разрешение прерываний
 
while (1) {}; // Бесконечный цикл
}

Есть ощущение что ошибки в настройке счетчика, но не хватает ни знаний ни смекалки понять где проблема. :)

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

Сб мар 07, 2015 11:34:29

Ну, как минимум, unsigned char cou1; не может достигнуть значения 2000. Используйте unsigned int, или период счётчика в 10 раз больше и считать тогда до 200. Хорошо бы ещё следить и за тем, чтобы счётчик, досчитав до максимума, больше не инкрементировался.
Второй момент - coul и flag хорошо бы сделать volatile, так как они изменяются в прерывании.

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

Сб мар 07, 2015 14:51:51

И дребезг кнопки фильтровать, можно программно, можно формирователем на 555

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

Сб мар 07, 2015 16:22:30

переосмыслил, переписал код с нуля, теперь я хотя бы понимаю что и где происходит. :)
на данный момент работает моргание диодом с кнопки, а вот счетчик никак не хочет отрабатывать :( всю голову сломал, пересчитал предделитель.
не пойму где я не прав? ну не загорается лампочка на "постоянку".
Код:
#include <avr/io.h>
#include <avr/interrupt.h>
 
volatile int cou1;  // назначаем переменную
volatile char Flag1; // переменная флаг

 
ISR (TIMER1_COMPA_vect)
{
if ((PINC&(1 << PC0)) == 0) // Проверка состояния переключателя
{
cou1 = cou1++;
}
}   
 
int main(void)
{
// настройки портов ввода и вывода
DDRB= 0b11111111; //определяем PORTB на выход
PORTB= 0b00000000;   // изначально все лампочки на порту B выключены

DDRD = 0b11111000; //устанавливаем первые три ножки на вход остальные на выход
PORTD= 0b00000111; //подключаем к первым трем ножкам подт резисторы остальные уст в 0
 
TCCR1A = 0x00;
TCCR1B = (1 << CS12)|(0 << CS11)|(1 << CS10)|(1 << WGM12); //предделитель clk/1024, режим таймера СТС
TCNT1 = 0x00;
OCR1A = 489; // максимальный предел счета (при 1 MHz это 500мс)
TIMSK |= (1 << OCIE1A); // разрешение прерывания по совпадению

cou1 = 0b00000000; // Присвоение начального значения
Flag1 = 0b00000000; //изначально сброшенный

sei(); // Разрешение прерываний
 
while (1)
{
   if ((PIND&(1 << PD0)) == 0) // если кнопка PD0 нажата
   {
      
      if(Flag1==0)
      {
         PORTB=_BV(0); //включить ламочку
      }
      else // если флаг не равен 0
      {
         Flag1=1; // установим флаг в 1 (лампочка горит)
      }
      
   };
   
   if ((PIND&(1 << PD0)) == 1) // когда кнопку отпустили
   {
      if(cou1< 4)        // проверяем достиг ли счетчик указанного значения
      {
         PORTB &= ~_BV(0);  //выключим лампочку
         cou1=0;            //сбросим счетчик
         Flag1=0;         // снимим флаг (лампочка не горит)
      }
      else // если достиг
      {
         //PORTB=_BV(0);       //включаем лампочку
         Flag1=1;         //устанавливаем флаг
         cou1=0;            //сбросим счетчик
      }
   }
   
   
}; // Бесконечный цикл
}
Ответить