Поиск сообщества
Показаны результаты для тегов 'avr'.
Найдено: 201 результат
-
Наткнулся на схемку в сети AVR JTAG ICE и решил её повторить. Дабы не тратить время на изготовление печатной платы решил предварительно собрать сей девайс "на соплях", вернее на беспаечной плате. Вот так у меня это всё получилось. Залил прошивку из статьи собрал схему с процом который будет целевым, соединил всё с COM портом и начал пытаться запустить всё из под CVAVR. Не заработало. Тогда попробовал из под Atmel Studio 4 и у меня всё получилось. Следующим этапом решил попробовать будет ли это всё работать через USB. И оказалось, что да, работает вполне хорошо. Нужно ещё попробовать из под последней Atmel Studio, но пока не на чем. Мне она не нравится из-за своей громоздкости и поэтому я ей не пользуюсь. Можно резюмировать, что схема по ссылке вполне пригодная, но использование её ограничено софтом. Для не слишком требовательных юзеров вполне годится. Буду рад любым комментариям, если что-то непонятно, спрашивайте, отвечу на ваши вопросы. Все материалы из вышеуказанной статьи выкладываю здесь, если кто захочет повторить, пожалуйста. mc85_AVR-JTAG-ICE.zip
-
В моём гнезде прибавление. В смысле, алгоритм вылупился. Не скажу, чтобы исключительно новый, вряд ли гениальный, но, мне кажется, заслуживающий внимания. Преамбула. Что мы понимаем под понятием "таймер"? Ну, не в смысле задатчика времени варки яиц всмятку, а в программировании? Это некая функция, которая "сама по себе" выполняется через заданные интервалы времени. Или же чуть иначе: функция выполнится через заданный интервал времени однократно. Наконец, и третья интерпретация тоже имеет место быть: таймер - это некий счетчик, который сам по себе считает, а мы можем время от времени поглядывать на его значение и принимать какие-то решения. Амбула. Как обычно реализуются таймеры в микроконтроллерном программировании? Безусловно, наиболее удобно - с задействованием аппаратных таймеров-счетчиков и прерываний от них. Существует вариант реализации и без этого, но сие удовольствие надо оставить пациентам более строгого режима лечения. С прерыванием от аппаратного таймера все понятно, но их количество (аппаратных счетчиков я имею ввиду) ограничено. И поэтому в общем случае используется модель "программных" таймеров на основе одного прерывания от аппаратного. Вот как, например, выглядит один из простейших вариантов: #define TIMER_CNT 5 static volatile uint8_t timer[TIMER_CNT]; // обработчик прерывания от таймера, вызывается каждую миллисекунду ISR(TIMER_vect){ for(uint8_t i=0; i<TIMER_CNT; i++){ if(timer[i]) timer[i]--; } } // вот так можно ограничить длительность цикла интервалом времени в 100 мс timer[0] = 100; while(timer[0]){ // что-то длительное if(какое-то-условие-неизвестно-когда-возникающее) break; } if(!timer[0]){ // из цикла вышли по таймауту } else { // из цикла вышли по условию } Вроде бы, все просто и понятно. И даже удобно. Я сам 100 раз так делал! Но есть и неприятности. Во-первых, надо постоянно следить за тем, какой "номер" таймера задействован в том или ином участке кода. Когда таймеров два или три - проблемы нет, а когда в разных функциях в разных модлях их по нескольку штук, можно и запутаться. Во-вторых, массив timer должен быть глобальным, что само по себе не страшно, но как-то не комильфо... В-третьих, сделать таймер не однобайтным, а двухбайтным, чтобы иметь возможность отсчитывать большие интервалы времени, уже так красиво не выйдет - следует обеспечивать атомарный доступ к значению счетчика... И главное: этот подход реализует только последний вариант таймера из числа рассмотренных в преамбуле, т.е. гибкость его ограничена. Путем нехитрых манипуляций можно заметно улучшить ситуацию. Хотя и несколько усложнив код: #include <util/atomic.h> #define TIMER_CNT 5 typedef uint8_t (*tmr_func)(void); typedef struct{ uint16_t counter; uint16_t duration; tmr_func func; } timer_t; static volatile timer_t timer[TIMER_CNT]; ISR(TIMER_vect){ for(uint8_t i=0; i<TIMER_CNT; i++){ if(timer[i].counter){ timer[i].counter--; if((timer[i].counter == 0) && (timer[i].func != NULL)) if(timer[i].func()) timer[i].counter = timer[i].duration; } } } void timer_start(uint8_t t, uint16_t duration, tmr_func f){ ATOMIC_BLOCK(ATOMIC_RESTORESTATE){ timer[t].counter = duration; timer[t].duration = duration; timer[t].func = f; } } uint8_t timer_out(uint8_t t){ ATOMIC_BLOCK(ATOMIC_RESTORESTATE){ return timer[t].counter == 0; } } // вот так можно заставить светодиоды мигать с разной частотой static uint8_t blink_led1(void){ PORTB ^= 1<<0; // светодиод на нулевой линии порта return 1; // для перезапуска функции } static uint8_t blink_led2(void){ PORTB ^= 1<<1; // светодиод на первой линии порта return 1; // для перезапуска функции } timer_start(0, 500, blink_led1); timer_start(0, 300, blink_led2); while(1){ // тут что-то делаем, а светодиоды тем временем мигают каждый по-своему } Разумеется, здесь уже и атомарность доступа к значению счетчика реализована (ценой вызова отдельной функции), и все вариаты из преамбулы тоже. Надеюсь, очевидно, что если переданная в таймер функция вернет 0, она больше не будет вызываться после того, как таймер истечет? Чем вам не RTOS в минимальном виде? Главное условие в применимости такого подхода - предельно быстрое исполнение таймерной функции. Но при использовании автоматов состояний этим способом можно решать большой спектр практических задач. Но проблема с "учетом" таймеров осталась. Да и если вы вдруг станете нуждаться в бОльшем количестве таймеров, чем TIMER_CNT, вам придется эту константу менять. И в случае, если вы модифицируете старый проект, и старое количество таймеров вам не нужно, то тоже надо это вручную менять. Мелочь, а неприятно. Хорошо было бы, если бы в любом месте кода описал свой отдельный static (т.е. невидимый другим) таймер, и пользуешься им. Не нужен -удалил его описание, и не пользуешься. А "система" сама заботится о том, чтобы таймер "тикал" или не "тикал", если не нужен. И обычно для этого используют возможности RTOS. Хотя... Хотя максимальное количество выделяемых RTOS таймеров позапросу пользователя тоже ограничено значением какой-то константы... Но и из этого исхода есть выход! Только об этом в следующий раз. Т.е. о самом главном я и не сказал...
-
Я начинающий программист, пытаюсь программировать микроконтроллеры в среде АВР. У меня возник вопрос, вот например у нас есть двоичная система исчисления где 3 мы можем записать так: 00000011, однако чтобы подать логическую 1 на третий порт микроконтроллера мы должны сделать следующую запись PORTC=00000100, т е существует некая разница между названиями портов и системами исчисления, в таком случае как мне используя 16 ричную систему исчисления подать напряжение на какую либо ногу порта.Я знаю что данная запись 0х01 подает логическую 1 на 0 ногу, а данная запись 0х10 на 4 ногу ,ну а как быть дальше? Как подать напряжение на 5 ногу порта? Если я в чем то заблуждаюсь - поправьте, если чего то незнаю расскажите. Заранее благодарю.
- 7 ответов
-
- программирование
- AVR
-
(и ещё 1 )
C тегом:
-
Поставил LUFA, следом абсолютно не нужный мне ASF. Но в упор не понимаю - как создать проект на базе этой библиотеки из студии? Приходится вручную копировать папку с заголовочниками LUFA, прописывать пути в makefile, лишние телодвижения по добавлению папки в свойства проекта. Если я это делаю всё вручную, то тогда для чего это расширение? Примеры я могу и так покрутить. ЗЫ - не слишком высокий скилл в юзании Atmel Studio/
-
Здравия всем ! Пожалуйста помогите разобраться . Пытаюсь написать прошивку для Atmega8 на С в Atmel Studio 7.0 . Программка простая ( небольшая ) ... по сути - частотомер ( только для небольшого диапазона частот ... примерно - от нескольких Гц , до нескольких десятков кГц ) . Импульсы считать со входа T0 ( PD4 ) ...микр-ра Atmega8a ( 28 pin ) . Использовать TCNT1 (16 bit) . Полученное число выводить на Lcd - nokia5110 . Как я понимаю прерывания не нужны , алгоритм простой : 1) инициализация дисплея и счетчика 2) остановить (запретить счет) счетчик AVR - ( CS12,CS11,CS10-прописать нули ) 3) обнулить ( отчистить) буфер дисплея и счетчика ( AVR ) 3) запустить бесконечный цикл : а) разрешить считать импульсы с T0 ( PD4 ) - ( CS12,CS11,CS10-прописать единицы ) б) задать паузу ( надеюсь правильно рассчитал - 10 мсек ) в) запретить считать - ( CS12,CS11,CS10-прописать нули ) г) вывести полученное значение со счетчика на дисплей ( СИЛЬНО НЕ СМЕЙТЕСЬ ... Я НАЧИНАЮЩИЙ . с АЦП AVR разобрался удачно , собрал схемку в протеусе , написал прошивку , спаял ... все работает . а вот с таймером завис надолго . есть много примеров в инете , но все слишком навороченные для меня . запутался . ) вот примерно что получилось с таймером ... упрощал как мог ...в общим не получается . подскажите где косяк .(только просьба - без лишних наворотов и по возможности с комментариями ... задача - не повторить чужую программу ... а разобраться самому ) //Atmega8A #define F_CPU 8000000 #include <avr/io.h> #include <avr/interrupt.h> #include <util/delay.h> #include "n5110.h" void presets(){ Lcd_init(); Lcd_clear(); TCCR1B =0x00; TCNT1=0000; TCCR0 |= (1 << CS01); } int main(void) { presets(); while (1) { TCNT1=0000; TCCR1B|=(1<<CS12)|(1<<CS11)|(1<<CS10); _delay_ms(10); TCCR1B &=~(1<<CS12)|(1<<CS11)|(1<<CS10); Lcd_prints(5,2,FONT_1X,(TCNT1)PSTR("Hz")); // КОМПИЛЯТОР РУГАЕТСЯ НА ЭТУ СТРОЧКУ Lcd_update(); } }
-
Привет всем. Помогите с кодом, нужно озвучить нажатие кнопки, подключенной к порту PB0, то есть просто издать короткий "бип" одной частоты (примерно 1000 Гц) и длительностью примерно 0.2 секунды. Везде, где искал, сразу создают кучу нот, разные тона, используют прерывания, мне же надо только один короткий бип. Выполняться оно должно в теле цикла: while (1) { while(PINB&0b00000001); // ждем нажатия на кнопку на порте PB0 <вот здесь должен быть бип> п.с. забыл добавить - выполняться код будет на Attiny13a
-
Как сделать устройство, выводящие на индикатор время, прошедшее с момента последней перезагрузки контроллера?
-
Всем привет! Дано: Контроллер подсветки рабочей зоны кухни, реализованный на Tiny 13A. Светодиодная лента длиной 2,3 метра, led 5050, 120 светодиодов/метр. Принципиальная схема устройства ниже: Код прошивки: #include <tiny13.h> #include <delay.h> int triggered = 0; int ontimer = 0; void main(void) { // Input/Output Ports initialization // Port B initialization // Function: Bit5=In Bit4=In Bit3=In Bit2=In Bit1=In Bit0=Out DDRB=(0<<DDB5) | (0<<DDB4) | (0<<DDB3) | (0<<DDB2) | (0<<DDB1) | (1<<DDB0); // State: Bit5=T Bit4=T Bit3=T Bit2=T Bit1=T Bit0=0 PORTB=(0<<PORTB5) | (0<<PORTB4) | (0<<PORTB3) | (0<<PORTB2) | (0<<PORTB1) | (0<<PORTB0); // Timer/Counter 0 initialization // Clock source: System Clock // Clock value: 37,500 kHz // Mode: Fast PWM top=0xFF // OC0A output: Non-Inverted PWM // OC0B output: Disconnected // Timer Period: 6,8267 ms // Output Pulse(s): // OC0A Period: 6,8267 ms Width: 0 us TCCR0A=(1<<COM0A1) | (0<<COM0A0) | (0<<COM0B1) | (0<<COM0B0) | (1<<WGM01) | (1<<WGM00); TCCR0B=(0<<WGM02) | (1<<CS02) | (0<<CS01) | (0<<CS00); TCNT0=0x00; OCR0A=0x00; OCR0B=0x00; while (1) { if (PINB.1==1) { triggered = 1; ontimer = 60; }; if (ontimer > 0) { ontimer--; } else { triggered = 0; }; if (triggered) { if (OCR0A<255) { OCR0A++; }; } else { if (OCR0A>0) { OCR0A--; }; }; delay_ms(10); } } Возникшая проблема: Греется полевой транзистор при работе. Изначально поискав информацию на данную проблему, начал прикидывать. Смотрим график зависимости пропускаемого тока стока (ID )от приложенного напряжения затвор-сток (VGS), при температуре окруж. среды 25 градусов: ID = 14 А (2,3 метра светодиодной ленты не могут столько кушать, по крайней мере я такую не видел). Было предположение что частота переключения ШИМ высокая - отсюда транзистор в не определенном состоянии = нагрев. Рассчитал макс. частоту так: Rg = 100 Ом, Vgs = 5V Заряд затвора: Qiss = Ciss * Vgs = 1800pF * 5v = 9nC Скрость нарастания: S = Rgate * Qiss = 100Ohm * 9nC = 0.009mV*sec Время на открытие или закрытие транзистора: t=S / Vgs = 0.002mV*sec * 3.2v = 4.5uSec Период - это открытие + закрытие: T = t + t = 4.5uSec + 4.5uSec = 9uSec Максимальная частота переключения: F < 1 / T = 1 / 9uSec = 111KHz Ток через затвор (G) и цифровой выход Tiny 13A: I = Qiss / t = 2mA Максимальный выходной ток GPIO у Tiny 13A 40.0mA 2mA < 40.0mA Выставил частоту ШИМ на 37,5 кHz. Вуаля - при подключении 1м светодиодной ленты (тестировал на обрезке), нагрева нет. Но как только подключил все 2,3 метра - транзистор стал снова спустя время греться, аж дотронуться не возможно. Захотел померить ток, который потребляет 1 метр ленты, проверить продавца. Потребление 1 метра ленты оказалось вместо заявленных 600 мА, все 1,85 А, причем заметил странную вещь - ток начал возрастать спустя время на сотые доли и дошел до 1,9 А. Дальше ждать не стал. Режим амперметра в мультиметре сломался? Далее подумал что слишком большая мощность рассеивается на транзисторе. Если учесть то, что при открытом транзисторе, его переход можно представить в виде линейного резистора с маленькой величиной сопротивления, можно рассчитать рассеиваемую мощность на транзисторе: Смотрим сопротивление транзистора в открытом состоянии при VGS = 5В : RDS(on) = 0.18 Ом P1 = 1,9*1,9*0,18 = 0,65 Вт. (1 метр св.ленты). Раз мы взяли потребление 1 метра ленты 1, 9 А, тогда 2,3 метра потребляют = 4,4 А. (Теперь не уверен в своем мультиметре). P2=4.4*4.4*0.18 = 3.5 Ватт - довольно таки многовато я думаю. В общем: Правильно ли я делаю расчеты? Что упустил? Как снизить нагрев транзистора, без применения вентиляторов и здоровенных радиаторов? Есть вариант замены светодиодной ленты на что нибудь поменьше жрущее (60 светодиодов/ метр например), но в будущем еще много раз придется сталкиваться с полевиками, хотелось бы разобраться .
-
Помогите написать простую задачку (для вас - простую, а я не шарю), на плате контроллера-конструнтора KIT-8515 нужно сделать вот это: "Пусть движковыми переключателями задаются два четырехзначных операнда. Напишите и протестируйте программу, при работе которой после нажатия кнопки 1 операнды складывались, а при нажатии кнопки 2 операнды вычитались, а результат операции выводился на светодиоды" Прикреплённый файл - начало задачки. Заранее благодарствую:) 123.rar
-
Здравствуйте! Мне нужно измерить длительность импульса. Для этого сначала применял внешнее прерывание, а теперь перешел на режим захвата таймера в Atmega 328. Однако сейчас происходит странное: Через определенное таймер просто останавливается. Гугл результатов не дает, ни у кого захват таймера 1 не останавливается. Подскажите пожалуйста, что делать? Среда разработки CodeVisionAVR v3.12. Сейчас попробовал версию 3.3, толку нет. Не работает. Код максимально упростил, но по прежнему толку ноль. Переполнение таймера 0 так же работает отлично, до тех пор, пока что-то не произойдет с прерыванием по захвату. Как только что-то произошло - мк останавливается... Может немножко подождать, и увеличить значение счетчика current_timp еще на пару значений... Совсем не знаю что делать. interrupt [TIM1_OVF] void timer1_ovf_isr(void) { TCNT1H = 0x00; TCNT1L = 0x00; } // Timer1 input capture interrupt service routine interrupt [TIM1_CAPT] void timer1_capt_isr(void) { TCNT1H = 0x00; TCNT1L = 0x00; // Это уже уровень танцев с бубном "авось поможет" - не помогает. current_timp++; // Все упрощено до максимума. Мне бы он хоть количество периодов для начала... // } } // Прерывание по переполнению первого таймера interrupt [TIM0_OVF] void timer0_ovf_isr(void) { // Обнуление счетного регистра. TCNT0=0x00; counter ++; if (counter > 10) { lcd_clear(); sprintf(buffer,"%d us", current_timp); lcd_gotoxy(0,0); lcd_puts(buffer); counter = 0; } } // Главный цикл программы void main(void) { #pragma optsize- CLKPR=(1<<CLKPCE); CLKPR=(0<<CLKPCE) | (0<<CLKPS3) | (0<<CLKPS2) | (0<<CLKPS1) | (0<<CLKPS0); #ifdef _OPTIMIZE_SIZE_ #pragma optsize+ #endif // Port B initialization // Function: Bit7=In Bit6=In Bit5=In Bit4=In Bit3=In Bit2=In Bit1=In Bit0=In DDRB=(0<<DDB7) | (0<<DDB6) | (0<<DDB5) | (0<<DDB4) | (0<<DDB3) | (0<<DDB2) | (0<<DDB1) | (0<<DDB0); // State: Bit7=T Bit6=T Bit5=T Bit4=T Bit3=T Bit2=T Bit1=T Bit0=T PORTB=(0<<PORTB7) | (0<<PORTB6) | (0<<PORTB5) | (0<<PORTB4) | (0<<PORTB3) | (0<<PORTB2) | (0<<PORTB1) | (0<<PORTB0); // Port C initialization // Function: Bit6=In Bit5=Out Bit4=Out Bit3=Out Bit2=Out Bit1=Out Bit0=Out DDRC=(0<<DDC6) | (1<<DDC5) | (1<<DDC4) | (1<<DDC3) | (1<<DDC2) | (1<<DDC1) | (1<<DDC0); // State: Bit6=T Bit5=1 Bit4=1 Bit3=1 Bit2=1 Bit1=1 Bit0=1 PORTC=(0<<PORTC6) | (1<<PORTC5) | (1<<PORTC4) | (1<<PORTC3) | (1<<PORTC2) | (1<<PORTC1) | (1<<PORTC0); // Port D initialization // Function: Bit7=Out Bit6=Out Bit5=In Bit4=In Bit3=In Bit2=In Bit1=In Bit0=In DDRD=(1<<DDD7) | (1<<DDD6) | (0<<DDD5) | (0<<DDD4) | (0<<DDD3) | (0<<DDD2) | (0<<DDD1) | (0<<DDD0); // State: Bit7=1 Bit6=1 Bit5=T Bit4=T Bit3=T Bit2=T Bit1=T Bit0=T PORTD=(1<<PORTD7) | (1<<PORTD6) | (0<<PORTD5) | (0<<PORTD4) | (0<<PORTD3) | (0<<PORTD2) | (0<<PORTD1) | (0<<PORTD0); // Делители таймера 0 рассчитаны таким образом , что его тактовая частота = 15,625 КГц. Расчет был на применение в схеме семисегментников, но с LCD индикатором будет информативнее. TCCR0A=(0<<COM0A1) | (0<<COM0A0) | (0<<COM0B1) | (0<<COM0B0) | (0<<WGM01) | (0<<WGM00); TCCR0B=(0<<WGM02) | (1<<CS02) | (0<<CS01) | (1<<CS00); TCNT0=0x00; OCR0A=0x00; OCR0B=0x00; // Настройка таймера 1 TCCR1A=(0<<COM1A1) | (0<<COM1A0) | (0<<COM1B1) | (0<<COM1B0) | (0<<WGM11) | (0<<WGM10); TCCR1B=(1<<ICNC1) | (1<<ICES1) | (0<<WGM13) | (0<<WGM12) | (0<<CS12) | (0<<CS11) | (1<<CS10); TCNT1H=0x00; TCNT1L=0x00; ICR1H=0x00; ICR1L=0x00; OCR1AH=0x00; OCR1AL=0x00; OCR1BH=0x00; OCR1BL=0x00; // Разрешение прерывания по переполнению таймера 0 TIMSK0=(0<<OCIE0B) | (0<<OCIE0A) | (1<<TOIE0); // Timer/Counter 1 Interrupt(s) initialization TIMSK1=(1<<ICIE1) | (0<<OCIE1B) | (0<<OCIE1A) | (1<<TOIE1);
- 4 ответа
-
- захват таймера
- Atmega328
-
(и ещё 1 )
C тегом:
-
Всем привет! Подскажите, пожалуйста, как правильно считать данные с внешней eeprom по шине spi, в данном случае 25LC256. Написал код ссылаясь на даташит. Собрал схему в протеусе, подключил spi отладчик и вот что получил в итоге. Так же не могу проверить получается записать данные в память или нет. Весь код прикрепил. main.c
-
Вот вы говорите: AVR слишком убоги, чтобы применять на них RTOS... А я рискнул... Сначала попытался рассмотреть имеющиеся варианты, чтобы сделать предварительные выводы. Поиск вываливает примерно с десяток готовых разработок RTOS разной степени крутости, из которых FreeRTOS, естественно, в лидерах. Однако, я оценил свои силы и решил, что вхождение в эту ОС для меня обернется большими сложностями, в основном, из-за большого количества возможностей API, и англоязычным их описанием. Ну не принимает душа русская языка аглицкого, даже со словарем и гуглопереводчиком в больших количествах. А из осей на великом и могучем нашлось только две: кооперативная OSA и присиплюсплюснатая ScmRTOS. Опять-таки из-за собственной ограниченности более современная и продвинутая ScmRTOS мне показалась недоступной - С++ пока что понимаю и принимаю исключительно в качестве наказания. Ну, собственно, и вышло, что начать и закончить поиск осей для AVR можно на OSA. Попробовал - получается. Не без скрипа, но работает. И даже увлекло меня это. Но вот что мне не понравилось в этом варианте. Главная особенность этой ОС, которую следует учитывать при работе (то есть при написании программ), это отсутствие сохранения контекста при переключении задач. Иными словами, если в текущей задаче вызывается сервис операционной системы, переключающий задачи, то все локальные переменные текущей задачи могу потерять свою актуальность. Это означает, в частности, запрет на вызов сервисов системы в циклах по счетчику (значение счетчика будет потеряно). И единственный способ решить эту проблему - вместо автоматических локальных переменных использовать static или вообще отказаться от локальных в пользу глобальных. Сами понимаете, это совсем не гуд. Вторая особенность этой ОС, это возможность вызывать сервисы ОС, преключающие задачи, только из тела самой задачи, но не в вызываемых из неё функций. То есть нельзя сделать функцию, например, ожидающую прием символа из USART при помощи системного сервиса OS_Wait, а затем вызывать эту функцию из разных задач, то есть поступать по аналогии с привычным "не-многозадачным" подходом. Вот представьте себе ситуацию: задачи формируют текстовые сообщения и выводят их в USART. Кажется логичным сделать функцию, которая занимается отправкой в USART строки посимвольно и использовать эту функцию во всех задачах - а нельзя! Более того, не смотря на то, что все задачи ПООЧЕРЕДНО формируют строки (ОС ведь кооперативная), каждая из задач должна иметь собственный промежуточный static-буфер для формирования своей строки - это ведь явно лишний расход памяти! При обычном подходе мы бы работали с локальным буфером в каждой функции, а локальный буфер, как известно, исчезал бы при выходе из функции... Наконец, архитектура этой ОС (под архитектурой я подразумеваю набор файлов-модулей и порядок работы с ними) такова, что почти все файлы инклюдятся друг в друга, что очень сильно нарушает модульный подход при программировании. Напомню, что модульный подход означает, в частности, возможность компиляции каждого Сишного файла отдельно от других сишных файтов. А в OSA системные сишники "вставляются" в один большой "общий" сишник, который затем и компилируется. В итоге я потратил немало времени, чтобы разобраться, как же настроить проект в Eclipse, чтобы можно было комфортно работать. Eclipse очень привык считать все сишники отдельными модулями проекта, и страстно стремится компилировать их отдельно. В общем, знакомство с OSA было увлекательным, недолгим, интересным, но разочаровывающим. Другие же ОС, найденные мной, были не кооперативными, а вытесняющими. Вытесняющие ОС имеют много преимуществ перед кооперативными, но один их недостаток сильно ограничивает применение на AVR: они весьма требовательны к объемам ОЗУ. Именно отсюда растут ноги у паникерских мнений, что AVR и "нормальная" RTOS - понятия несовместимые. И это на самом деле так, если мы говорим о микроконтроллерах младше (т.е. слабее) atmega32. Для справки: OSA вполне себе способна быть полезной не только на atmega8, но даже и на attiny2313! Но, к счастью для меня, не одной atmega32 ограничен мир AVR, и, кроме прочего, не ограничен и я сам. У меня в загашнике есть и at90can128, и даже atmega2560! И, спросил я себя, почему я должен переживать по поводу вытесняющей ОС при таких-то ресурсах? В at90can128 целых 4К ОЗУ, а уж flash-памяти по 8-битным меркам просто немеряно - 128К, а у монстра atmega2560 вдвое больше всего! Правда, если первый МК паять вполне комфортно (TQFP64), то второй без микроскопа уже сложно (TQFP100 c шагом выводов 0,5 мм). А тут еще у меня завалялась отладочная платка DVK90CAN1... Ну, вы поняли... Итак, решающим теперь для меня стал поиск максимально простой операционки - чтобы мне по силам. Их не так мало, как может показаться, но самой простой, по моему мнению, является YAVRTOS (скачать архив с исходниками, примерами и документацией можно по ссылке, но сайт автора уже не существует) - это практически такой же малоизвестный, как OSA, продукт примерно тех же времен (видимо, тогда было можно каждому мастерить свою собственную ОС с блекджеком и девушками низкой социальной ответственности). Не смотря на инглиш, эта ось оказалась мне по силам: всего два файла и с полтора десятка системных функций! За один вечер легко расщелкал все необходимое для первого старта. Плюсы этой RTOS перед OSA неоспоримы: не надо предпринимать практически никаких усилий по оформлению кода - пишется точно так же, как всегда, с локальными переменными, с вложенными вызовами функций и т.д. Разумеется, надо следить за общими ресурсами и блокировать к ним доступ, если необходимо - но это вообще всегда необходимо в многозадачных системах, и даже в ОSA частично так. Минусы, правда, тоже заметны: минимальное приложение, тупо мигающее двумя светодиодами (каждый в своей задаче) занимает почти 2К flash и порядка 400 байт ОЗУ. На просторах выбранного мной МК это даже и не заметно, но для atmega8 может быть близким к техническому пределу. YAVRTOS написана на 99,9% на Си (только сохранение/восстановление контекста реализовано в виде ассемблерной вставки из трех десятков push-pop), всего два файла (task.c и task.h) - все это явный плюс в плане изучения и модификации под себя, если надо (и если хватает ума). Косвенным плюсом (или минусом, если продолжать переживать о ресурсах) является массовое применение malloc в ядре ОС, а значит, и в пользовательском приложении уже вполне оправдано динамическое распределение памяти. И мой энтузиазм просто на взлете от первого опыта! Например, вот как выглядит код задачи и вспомогательных функций для извлечения точного времени из GPS-приемника, подключенному к USART1, и вывода этих показаний на стандартный вывод (stdout, связанный с USART0): const __flash char gps_msg[] = "RMC,"; #define GPS_MSG_SZ (sizeof(gps_msg)-1) // поллинг 1 символа от GPS static uint8_t get_char(void){ while(bit_is_clear(UCSR1A, RXC)) wait_for_increment_of(&tick, 1); return UDR1; } // получение 1 цифры из символа static uint8_t get_dig(void){ return (get_char() - '0'); } // собственно сама задача void p2p_usart(void *p){ uint8_t i; uint8_t h,m,s; while(1){ i = 0; // ждем прихода сообщения с точным временем while((i < GPS_MSG_SZ) && (get_char() == gps_msg[i])) i++; if(i == GPS_MSG_SZ){ // разбираем сообщение по символам h = get_dig()*10 + get_dig() + 3; // +3 - это часовой пояс h %= 24; m = get_dig()*10 + get_dig(); s = get_dig()*10 + get_dig(); // пропускаем сотые доли секунды get_char(); // '.' get_char(); // 's' get_char(); // 's' get_char(); // ',' // проверка корректности времени и его вывод if(get_char() == 'A'){ printf_P(PSTR("GPS Time %02d:%02d.%02d\r"),h,m,s); } else { printf_P(PSTR("No GPS, wait... \r")); } } } } Как видите, код крайне "тупой", то есть прямолинейный, как лом: сплошные ожидания и никакой заботы о том, что параллельно должно что-то еще работать. В моем случае просто мигают 2 светодиода - один с длительностью импульса/паузы в 500 тиков, а второй в 501 (кстати, 1 тик = 1 мс, тактовая частота МК = 8 МГц). Но вместо светодиодов может быть еще две (или сколько надо) аналогично прямолинейно написанных задач, и можно быть уверенным, что все будет работать! Приведу данные по итогам компиляции проекта, чтобы продемонстрировать израсходованные ресурсы: Не так уж и плохо, учитывая свободное применение printf. В активном режиме используется дополнительно 380 байт ОЗУ под стеки задач и ОС, т.е. примерно 10% всего объема - еще много остается. Есть, кроме YAVRTOS, и другие альтернативы, например, FemtoOS, которая поддерживает даже (!!!) attiny25, и при этом тоже является вытесняющей операционкой. Но она существенно "богаче" в плане API, и разобраться с нею будет посложнее, т.к. документирована она явно менее детально. Возможно, я и её попробую на вкус... И, скорее всего, теперь это станет для меня основным способом написания программ. RTOS позволяет сильно упростить себе жизнь. Имхо.
-
Здравствуйте. Делаю бегущую строку на AVR и драйверах max7219 по этой статье. Исходный код есть в конце статьи. Хотел бы доработать устройство чтобы можно было передавать сообщение через Bluetooth модуль HC-05 при помощи Bluetooth terminal. Сам знаю как это можно сделать, т.к. все примеры находил только под Arduino. Прошу помочь кто знает как это можно реализовать
-
Здравствуйте. Часто прошивал МК, в один из моментов по программе должна была выставляться единица на 5Б пин. После этого убрал эту функцию, но теперь при включении к питанию МК на любой прошивки пин уходит в ноль и МК не отвечает ни на UART, ни на I2C. Пин не уходит в ноль только на чистом кристалле. Даже если в новой прошивке и слома нет про включение этого пина, он в единице. Может ли это означать, что программная память посыпалась? Спасибо.
-
Всем привет. Хочу сделать светодиодную матрица с драйвером max7219 на Atmega324P. При попытке смоделировать в Proteus вылазят ошибки: Собирал вроде всё правильно, текст в EEPROM загружен, но на матрицах выводится непонятно что и на всех одно и тоже. Может я что-то напутал, когда собирал(( Подскажите пожалуйста кто знает)) Проект со схемой Proteus и прошивку прикрепляю. И просто схема: Строка c MAX7219.rar
-
добрый день. Вернулся к микроконтроллерам после длительного перерыва. Сижу туплю и даже гугл не помог. Два вопроса по Atmel Studio 7. Режим отладки. Симуляция. 1. Как включить окно в котором можно посмотреть что контроллер выплевывает в UART? Не содержимое регистра, а типа терминала. 2. Как подсунуть студии файлик с содержимым EEPROM?
-
Всех приветствую! Сам я программирую на стандартной среде ардуинки, и в одном проекте потребовалось увеличить частоту ШИМ на портах 5,6,9,10,11,13 Arduino Micro. На этой ардуино стоит Atmega32u4, есть тут знатоки avr? Как повысить частоту на этих пинах?
-
Доброго дня всем! Не так давно решил опробовать использовать в схемах ATmega в корпусе TQFP и возник такой вопрос. На ней имеется аж три ноги на "-" и две под "VCC". Подсоединять нужно все или можно только по одной любой? Заранее благодарен за помощь.
- 16 ответов
-
Добрый день, ситуация такая - попались мне под руку куча рассыпухи в числе которых достаточное количетво тинек и прочей лабуды - пытась хеловродить, попробовал взять готовый пример работы тиньки и лсдишника здесь также имею ардуинку как Айсипи и чудесно мигаю светодиодом на мк прошитом ею же так вот при попытке залить код который по ссылке чуда не произошло. курение мануалов лсдишника дало понять лиш одно что старший и младший биты одинаковы с лсдишником со статьи - лсдишник рабочий (игрался контрастом одной строки через V0 и потенциометр ) - как в прочем и мк, было задумано ковырнуть все это в протеусе и атмельстудии, но результатом не увенчалось. Пожалуйста тыкните носом что да где не так. fail.zip
-
Всем доброго времени суток! В AVR-ках я новичёк и очень нуждаюсь в вашей помощи. Задача у меня следующая. Есть драйвер управления серводвигателем на ATmega88. Помимо основной задачи ATmega88 через 74HC164D выводит на сдвоенный 7-ми сегментный индикатор направление вращения мотора в виде анимации (вращает сегмент по или против часовой стрелки). Рядом есть некая поделка на ATmega8, одной из задач которой является определение направления вращения мотора и, в зависимости от направления, выполнение различных действий. Как мне это сделать? Как подружить две меги? Всем заранее спасибо.
-
Всем доброго времени суток. Развел платки - коммутаторы на основные МК. Платы коммутационные для HV PROG (параллельного программирования). Питание 5в оставил для перемычки (видно на фото). Комплект из 3-х плат ATMEGA 8, 16, 32, 48(P), 88, 164P, 168, 324P, 664P, 1284P, 8535, ATTINY 48, 2313. https://radikal.ru/fp/4f4203a9b1d54f9fbb92318c2234e576 Имею 5 комплектов. Цена 450 за все 3 платки ("лист" на этой фотографии) Имею 5 комплектов. https://radikal.ru/fp/73ce63f7f99b4f7d9b744b2563204c1b Платки находится в Самаре, если почтой то +50р почте.
-
Всем привет! Возникла следующая проблема: Есть две ардуины 'Mega2560'. По несчастливому стечению обстоятельств данные платы попали в руки одному чуваку, который, вернув их, заявил, что они перестали работать после того, как он "чисто ради интереса" поковырял на обеих некоторые фьюзы. Есть у меня такой китайский usbasp v2 программатор: Подключив данный девайс к ICSP-пинам первой платы, удалось без проблем восстановить на ней загрузчик через стандартную Arduino-IDE, после чего работоспособность платы полностью восстановилась. Но вот при попытке сделать то же самое со второй платой, получаю это: Такое же сообщение получаю при попытке зашить загрузчик в неподключенную к программатору ардуину, то есть программатор вообще не видит МК. Плата прекрасно работала до того, как вышеупомянутый товарищ покрутил настройки фьюзов. Что я пытался предпринять: Замыкал пины JP3 программатора, отвечающие за понижение скорости, подключал к ардуине 5V от внешнего источника при прошивке загрузчика, - не помогло. Поиском пользоваться умею, аналогичную тему тут находил, но там проблема была в том, что парень неверно подключал программатор к контроллеру. В моём же случае всё подключено верно, повторюсь, что загрузчик первой платы этим же программатором был восстановлен успешно. Буду рад любым советам касательно того, как восстановить работоспособность платы.
- 2 ответа
-
- arduino
- atmega2560
-
(и ещё 1 )
C тегом:
-
Здравствуйте. Подскажите пожалуйста, возможно ли на attiny13 реализовать такую штуку. Мне в процессе работы программы нужно поменять режим работы таймера/счетчика с fast PWM на обычный счёт, отсчитать длительный промежуток времени и опять вернутся в режим ШИМ. Т.е. я подаю на ногу сигнал ШИМ и когда он в максимальном значении, я его отключаю, и тупо подаю на ногу высокий лог. уровень. В это время Т/С по идее свободен, и мне надо посчитать время работы выхода на максимальном лог. уровне, при достижении какого-то значения времени нужно перевести т/с обратно в ШИМ. Возможно ли это? И как приблизительно это реализовать
- 1 ответ
-
- микроконтроллер
- AVR
-
(и ещё 2 )
C тегом:
-
Здравствуйте. Требуется вывести данные температуры и влажности на экран. С LCD дисплеем разобрался, осталось разобраться с SHT21. Постоянно выводит 0 на дисплей: Main.c: #define F_CPU 8000000UL #include <avr/io.h> #include <avr/interrupt.h> #include <util/delay.h> #include <stdio.h> #include <stdlib.h> #include "globals.h" #include "LCD_lib.h" #include "twi.h" // I2C #include "sht21.h" int main(void) { I2C_Init(); _delay_ms(100); LCD_init(); char buffer[20]; roomAdrInit(); SHT21_reset(); while(1) { SHT21_reset(); LCD_sendString(itoa((int)get_temperature(), buffer, 10), 4, 0, 0); _delay_ms(1000); } } twi.c: #include <avr/io.h> #include "twi.h" void I2C_Init(void) { TWSR = 0; TWBR = 0x20; TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN); } void I2C_StartCondition(void) { TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN); while(!(TWCR & (1<<TWINT))); } void I2C_StopCondition(void) { TWCR = (1<<TWINT)|(1<<TWSTO)|(1<<TWEN); } void I2C_SendByte(uint8_t data) { TWDR = data; TWCR = (1<<TWINT) | (1<<TWEN); while(!(TWCR & (1<<TWINT))); } unsigned char I2C_ReadByteAck(void) { TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWEA); while(!(TWCR & (1<<TWINT))); return TWDR; } unsigned char I2C_ReadByteNak(void) { TWCR = (1<<TWINT) | (1<<TWEN); while(!(TWCR & (1<<TWINT))); return TWDR; } sht21.c: #define F_CPU 8000000UL #include <avr/io.h> #include <util/delay.h> #include <stdlib.h> #include <stdio.h> #include "twi.h" #include "sht21.h" void SHT21_reset() { unsigned char reg[1]; reg[0]=SHT21_reset_cmd; I2C_StartCondition(); I2C_SendByte(SHT21_i2c_write); I2C_SendByte(*reg); I2C_StopCondition(); _delay_ms(100); } uint16_t checksum(unsigned char data[],uint8_t byte, uint8_t check) { uint8_t crc=0; uint8_t bytectr,bit; for (bytectr=0; bytectr<byte;bytectr++) { crc^=(data[bytectr]); for (bit=8;bit>0;bit--) { if(crc&0x80) { crc=(crc<<1)^polynomial; } else { crc=crc<<1; } } } if (crc!=check) { return 0; } else { return data; } } void write_user_register() { unsigned char reg[3]; reg[0]=user_register_write; reg[1]=0x44; I2C_StartCondition(); I2C_SendByte(SHT21_i2c_write); I2C_SendByte(*reg); I2C_StopCondition(); } uint16_t read_value(uint8_t reg) { char data[4],crc; uint16_t result; data[0]=reg; I2C_StartCondition(); I2C_SendByte(SHT21_i2c_write); I2C_SendByte(reg); I2C_StartCondition(); I2C_SendByte(SHT21_i2c_read); data[1] = I2C_ReadByteAck(); data[2] = I2C_ReadByteAck(); crc=I2C_ReadByteNak(); I2C_StopCondition(); result=(data[1]<<8) | data[2]; checksum(result,4,crc); result &= 0xFFFC; return result; } float get_humidity() { //char buffer2[4]; uint16_t hum_value = read_value(humidity_hold_mode); return -6 + 125.0 / 65536.0 * hum_value; //dtostrf(rh,5,2,buffer2); _delay_ms(100); } float get_temperature() { //char buffer1[4]; uint16_t temp_value = read_value(temperature_hold_mode); return -46.85 + 175.72 / 65536.0 * temp_value; //dtostrf(tc,5,2,buffer1); _delay_ms(100); }
-
- Atmega328P
- AVR
-
(и ещё 1 )
C тегом:
-
Я новичок в программировании AVR контроллеров, хотя знаю +/- C++. Проблема заключается в том, что я не могу написать прошивку к своему маленькому проекту. Используемый мною контроллер - ATTiny45. У него на борту имеется 1 АЦП с выходом на 4 ноги. Нужно, чтобы фактически одновременно брался замер с 3, 4 и 5 порта по АЦП, и при появлении 1 на одном из них МК должен подать 5В на 1 или 2 порты. Источник АЦП AREF. Сюда прикреплю схему самого робота, если кого не затруднит помочь написать прошивку, буду очень благодарен