В каждом языке программирования есть такое понятие «Hello World». Это первая программа, дающая общие понятия о структуре программы. Для микроконтроллеров первая программа мигание светодиода. Это самое простое и наглядное.
Сначала нужно написать программу, используя CodeVision (C avr). Далее есть 2 варианта:
1. Прошить виртуальный микроконтроллер (используя программы симуляторы).
2. Прошить реальный микроконтроллер.
1. Схема собирается в симуляторе Proteus. Чтобы прошить виртуальный микроконтроллер, нужно указать где у вас на жестком диске хранится файл прошивки.
Плюсы: бесплатно, быстро, просто, достаточно наглядно, не требующий навыков сборки схемы. Минусы: результат не подкреплен практикой, значит есть шанс что все быстро забудется.
2. Тут множество вариантов, но как минимум нужен:
2.1. программатор AVR микроконтроллеров,
2.2. ATmega8-16PU (PDIP28 в дип корпусе),
2.3. резистор 1к,
2.4. светодиод,
2.5. проводки,
2.6. 5В стабилизированный источник (блок питания на 5В, питание usb компьютера),
2.7. много свободного времени и желания.
По желанию:
2.8. макетная плата (можно попробовать навесным монтажом),
2.9. паяльник (можно извратиться и без него),
2.10. разъем (можно извратиться и без него),
Минус только один — денежные вложения, которые я считаю в дальнейшем отобьются. Остальное все плюсы. Самое дорогое это программатор. Как решать задачу ваше дело, я покажу оба варианта.
Схема нашего устройства.
Ищем, качаем свежий Proteus. В пакете протеуса нас интересует только ISIS 7. Если вы решили собирать все руками, идем на ближайший радиорынок или магазин электроники и покупаем все, что нужно. Купили, скачали, поставили. Как создать проект в CAVR можно узнать тут
1. Запускаем CodeVisionAVR
2. В окне мастера настроек, переходим на вкладку Ports и устанавливаем значение Bit 0 = Out. Создаем, сохраняем проект.
3. Вычищаем код:
#include <mega8.h> void main(void) { PORTB=0x00; DDRB=0x01; while (1) { }; } |
4. Теперь можно писать наш код.
#include <delay.h> | позволяет использовать временные задержки, например делать паузы между зажиганием светодиода |
delay_ms(100); delay_us(100); |
позволяет сделать задержку в программе 100мс, позволяет сделать задержку в программе 100мкс |
PORTB.0=1; PORTB.0=0; |
включает ножку 0 порта В (напряжение +5В), включает ножку 0 порта В (напряжение 0В) |
5. Добавляем в наш бесконечный цикл программы мигания светодиодом
#include <mega8.h> #include <delay.h> void main(void) { PORTB=0x00; DDRB=0x01; while (1) { PORTB.0=1; //включаем 0 ножку порта В delay_ms(100); // ждем 100 мс PORTB.0=0; //выключаем 0 ножку delay_ms(100); //ждем 100 мс }; }; |
6. Компилируем, прошиваем (как прошить можно почитать тут). Фьюзы для данного урока должны быть выставлены так:
Данная конфигурация фьюзов позволяет запустить микроконтроллер от внутреннего генератора на 2МГц. После прошивки светодиод будет мигать.
Запилил видео, чтобы был более понятен сам процесс, удачи в ваших начинаниях.
Update: Добавлен тест, в котором вы можете проверить на сколько хорошо вы усвоили материал урока
Приветствую есть вопрос! Собственно пытаюсь сделать в одном цикле мигание светодиодов, а также их постоянное включение то есть, У меня есть PORTB 1,2 и 3 они должны мигать, а PORTB 4,5 и 6 должны постоянно гореть и все это в одном цикле. Буду признательн хоть за какую подсказку.
Уже не нужно спасибо проблема решена))
Уважаемый админ я пишу не к теме но думаю многих заинтересует RFID ключи как с ними работать как писать програму
Уважаемый админ про RFID ключи скажите хоть что нибуть или не знаете ?
Виктор, я их никогда не юзал
жаль но на этом тоже спасибо ото все жду ответа .Но как я понял там работает шим, если чо то дайте знать пжалуста ото на ассамблере есть но не очень пнятно что к чему особенно новичку
Проверял 3 атмеги две на 16 и 32, на всех одно одно и тоже: PORTC.0 и PORTC.1 светодиод мигает, PORTC.2 тускло светит.
у меги16 вроде jtag надо отрубать
Спасибо, заработало. А на какой частоте МК пауза будет соответствовать реальному времени (+-погрешность), как я понял длительность паузы зависит от частоты работы МК.
Под какую частоту проект, под такую же надо фьюзы выставлять, тогда все будет ок
скажете пожалуста восле несколько программирований и стираний кристала перед программированием стала вылезать ошибка:flash buffer is empty после стирания ничего не меняется подскажите что желать 😥
нужно выбрать файл прошивки, .hex
помогите разобраться как сделать на тини 13 шим стабилизатор по АЦП. на меге8 делал, а тут не получается, может что в тини нет ноги опортного напряжения. хочу точно выставить напряжение
читаем даташит на тиньку:
10-bit ADC with Internal Voltage Reference
т.е. источник опорного реализован внутри микроконтроллера
скажите пожалуста почему в proteuse delay_ms(1000) ;ровно примерно 1 секунде но на железе мега8 это не так . как надо устанавливать биты чтоб заданное время совпадала?
Заране спасибо
Как то так
Почему вы выбрали именно CodeVision ?
У него все библиотеки идут в комплекте.
Добрый день. Подскажите, как погасить светодиод не на 100 мс, а на 24 часа? Функция delay перегрузится если указать ей 24 часа в миллисекундах и сработает ни корректно. Каким методом можно воспользоваться?
for(i = 0; i < 24; i++) { delay_ms(1000); }
Это задержка на 24 секунды, а не 24 часа.. Для таких чумавых задержек нужен таймер с прерывание, а то пока функция будет обрабатываться МК будет просто все это время тупить а месте.
Чет залил указал я созданный hex в Proteus, а светодид не мигает… На потру PB0, векзде висит серый квадратик… Только на PC6 крвсный.
У вас ещё 153 строки скомпилировало, а у меня почему-то 655!
Все, завмигал. Как-то неправильно создавал проект в Proteus, вместо нужной прошивки, постоянно подставлялся какой-то левый obj. Хотя всё равно не есть непонятность…. Вы при создании проекта в CodeVisionAVR указали частоту 8Mhz, а при компилировании, информации о частоте вообще нету….
CAVR автоматически подгоняет длительности пауз и прочие задержки под выбранную частоту проекта. Иногда это может сказаться критически на прошивке, иногда нет. Например, если включать и выключать ножку по нажатию кнопки, то вообще никакой разницы что на 1, 2, 4, 8, 16МГц. Если создать проект на 1МГц и использовать задержки в 1с, но на практике использовать кварц на 2МГц, то задержка просто станет в 2 раза меньше, т.е. 500мс, но это не значит что прошивка не работает. Частота проекта это просто число, относительно которого рассчитываются временные отрезки в прошивке. Посмотреть и изменить ее можно в настройках проекта
Скажите пожалуста можно ли ожевить мегу 8 после неудачной прошивки в интер. много всякого пробывал не получилась
если неудачная прошивка это фьюзы, то ищите схему фьюз доктора
пробовал собирал не помагает вот и задумался такое бывает ?
Залочить мегу можно только фьюзами, если их не трогали, то она не может помереть сама, единственный вариант еще — где нибудь коротнуть
уважаемый админ я думаю будет спроведлива если вы напишете нам какие именно вообше не трогать фьюзи . чтом мк работал только с внутренним рц , а то нам новечкам пока трудно приходится
уже все написано, читайте http://avr-start.ru/?p=1065
ОГРОМНОЕ СПАСИБО ЗА ВАШ КУРС ПО AVR!!! Обязательно изучу все уроки!!!
Здравствуйте уважаемый админ!
Я только начинаю работать с контроллерами и прошу помощи.
Собрал счетчик на ATTiny2313, энкодэре и семисигментном индикаторе. При вращении энкодера вправо счет увеличивается, влево — уменьшается.При достижении 999 обнуляеться.
При значении 000 и вращении влево уменьшается (999,998,997…). Как мне сделать, чтоб при переходе через «0» я получил такие значения(-001, -002, -003…)
Буду благодарен, если подскажете как погасить ноли в старших разрядах.
Ниже привожу код, при необходимости могу скинуть файл протеуса и прошивку
/*
* Indikacia.c
*
* Created: 09.03.2015 22:48:11
* Author: Администратор
*/
#define F_CPU 1000000L // частота генератора
#include
#include
#include //поддержка прерываний
#define digit_display_time 1
int sotki=0; //начальное положение переменных char
int desyatki=0;
int millimetrs=0;
int ten_millimetrs=0;
int dig=255;
int button;
void init_io(void);
void init_int(void);
void init_io(void)
{
PORTB=0xFF; // подтягиваем на выводы 1
DDRB=0xFF; // определяем порт В как выходы (0-входы, 1-выходы), 0xFF=0b11111111
PORTD=0b11111111; // подтягиваем на выводы 1
DDRD=0xF8; // определяем порт D как выходы (0-входы, 1-выходы), 0xF8=0b11111000
}
void init_int(void) //определитель внешнего прерывания (вроде по переднему фронту)
{
GIMSK=(1<<INT0);
MCUCR=(1<<ISC00)|(1<<ISC01);
sei();
}
SIGNAL(INT0_vect) { //внешнее прерывание
cli();
if((PIND & (1 <9)
{
sotki=0;
desyatki++;
}
if ( desyatki>9 )
{
desyatki = 0;
millimetrs++;
};
if (millimetrs >9 )
{
millimetrs = 0;
sotki=0;
desyatki = 0;
};
}
if((PIND & (1 << PD0)) == 1)
{
sotki—;
if(sotki<0)
{
sotki=9;
desyatki—;
}
if(desyatki<0)
{
desyatki=9;
millimetrs—;
}
if(millimetrs<0)
{
millimetrs=9;
}
}
sei(); // разрешение прерывания
}
int main(void) // главная функция
{
unsigned char digits[10]={192,249,164,176,153,146,130,248,128,144}; //массив для генерации цифр. Какой элемент массива будет отправлен в порт, такая цифра и загорится.
init_io();
init_int();
while (1)
{
PORTD =~(1<<3); //включаем первый индикатор
PORTB = dig; //выводим на него
_delay_ms(digit_display_time); //ждем, время индикации одного разряда задается в заголовке программы
PORTD &=~(1<<3); //выключаем первый индикатор
PORTD =~(1<<4);
PORTB = digits[millimetrs];
_delay_ms(digit_display_time);
PORTD &=~(1<<4);
PORTD =~(1<<5);
PORTB = digits[desyatki];
_delay_ms(digit_display_time);
PORTD &=~(1<<5);
PORTD =~(1<<6);
PORTB = digits[sotki];
_delay_ms(digit_display_time);
PORTD &=~(1<<6);
if((PIND & 1<<1)==0 && button==0)
{
_delay_ms(1);
sotki=0;
desyatki=0;
millimetrs=0;
button=1;
}
if(PIND & 1<<1)
{
button=0;
}
}
}
чтобы использовать отрицательные числа, нужно чтобы переменные были signed, т.е. signed int, signed char…
Спасибо за совет, но ведет себя так же.
Могли бы вы мне показать образец, как должен выглядеть код?
Колонка «signed char digits[10]={192,249,164,176,153,146,130,248,128,144}; //массив для генерации цифр. Какой элемент массива будет отправлен в порт, такая цифра и загорится.» служит для вывода информации на семисегментник.
И как мне вывести «-» на первый индикатор(там пока пустой индикатор)?
if((result < 0) && (pos == 0)) PORTx = xx; xx - это знак минуса
Открываете калькулятор, режим программиста, вводите туда «0» 192, переключаете в бинарный вид (Bin), получите: 11000000. Каждый нолик зажигает какой то сегмент. Крайний левый это точка, 2ая слева 1ка это как раз ваш минус ( в 0 он не горит). Теперь зажигаете тоько его. Получиться 10111111. Переключаете в десятичный вид, вуаля: 191
PORTx = 191;
Прошу прощения! Не тот код выложил
Вот тот, о котором говорил
/*
* Indikacia.c
*
* Created: 09.03.2015 22:48:11
* Author: Администратор
*/
#define F_CPU 1000000L // частота генератора
#include
#include
#include //поддержка прерываний
#define digit_display_time 1
int sotki=0; //начальное положение переменных char
int desyatki;
int millimetrs;
int ten_millimetrs;
int dig=255;
int button;
int chislo;
int Danie;
void init_io(void);
void init_int(void);
void init_io(void)
{
PORTB=0xFF; // подтягиваем на выводы 1
DDRB=0xFF; // определяем порт В как выходы (0-входы, 1-выходы), 0xFF=0b11111111
PORTD=0b11111111; // подтягиваем на выводы 1
DDRD=0xF8; // определяем порт D как выходы (0-входы, 1-выходы), 0xF8=0b11111000
}
void init_int(void) //определитель внешнего прерывания (вроде по переднему фронту)
{
GIMSK=(1<<INT0);
MCUCR=(1<<ISC00)|(1<<ISC01);
sei();
}
SIGNAL(INT0_vect) { //внешнее прерывание
cli();
//*******************************//
//*******************************//
if(chislo= 100 )
{
Danie = Danie — 100;
millimetrs++;
}
//============
while( Danie >= 10 )
{
Danie = Danie — 10;
desyatki++;
}
//============
sotki= Danie;
}
//*******************************//
//*******************************//
if(chislo<0)
{
dig=191;
}
else
{
dig=255;
}
if((PIND & (1 << PD0)) == 0) //вход внешнего прерывания вращение вправо
{
chislo++;
}
if((PIND & (1 << PD0)) == 1) //вход внешнего прерывания вращение влево
{
chislo—;
}
sei(); // разрешение прерывания
}
int main(void) // главная функция
{
unsigned char digits[10]={192,249,164,176,153,146,130,248,128,144}; //массив для генерации цифр. Какой элемент массива будет отправлен в порт, такая цифра и загорится.
unsigned char digits[B]={255};
init_io();
init_int();
while (1)
{
PORTD =~(1<<3); //включаем первый индикатор
PORTB = dig; //выводим на него
_delay_ms(digit_display_time); //ждем, время индикации одного разряда задается в заголовке программы
PORTD &=~(1<<3); //выключаем первый индикатор
PORTD =~(1<<4);
PORTB = digits[millimetrs];
_delay_ms(digit_display_time);
PORTD &=~(1<<4);
PORTD =~(1<<5);
PORTB = digits[desyatki];
_delay_ms(digit_display_time);
PORTD &=~(1<<5);
PORTD =~(1<<6);
PORTB = digits[sotki];
_delay_ms(digit_display_time);
PORTD &=~(1<<6);
if((PIND & 1<<1)==0 && button==0)
{
_delay_ms(1);
chislo=0;
sotki=0;
desyatki=0;
millimetrs=0;
button=1;
}
if(PIND & 1<<1)
{
button=0;
}
}
}
Почему-то выделенная часть изменяется
Там такой код
if(chislo= 100 )
{
Danie = Danie — 100;
millimetrs++;
}
//============
while( Danie >= 10 )
{
Danie = Danie — 10;
desyatki++;
}
//============
sotki= Danie;
}
После целого дня глядения в монитор, уже не в силах вникать в такой код, или спрашивайте конкретные вопросы или выкладывайте проект целиком со схемой протеуса. Как минимум все переменные в CAVR unsigned, т.е. беззнаковые, если не указано ключевое слово signed, соответственно оно не может быть отрицательным, у Вас в проекте не увидел ни одной signed int. Отлаживайтесь по частям, уменьшайте/увеличивайте свою переменную просто задержками и посмотрите на то что выводится на индикаторы, потом приладите кнопки, прерывания.