Нескольно простых вопросов о программировании AVR на Си.
Re: Нескольно простых вопросов о программировании AVR на Си.
Ну почему же! Спорт у каждого свой. Как и смысл.)
- Реклама
-
elektronic3452
- Родился
- Сообщения: 16
- Зарегистрирован: Чт сен 12, 2024 21:34:21
- Откуда: Москва
Re: Нескольно простых вопросов о программировании AVR на Си.
Добрый вечер! Форумчане!!!
Я начинающий! Можете подсказать что значит строка PORTC = 0x3F & led_buff[0]; в этом коде?
#include <mega8.h>
#include <delay.h>
#define ON 1
#define OFF 0
#define timer_ TCNT0
#define timer_tact TCCR0
#define OUT PORTB.0
#define enable PINB.3
#define up PINB.4
#define down PINB.5
#define pwm__ OCR1AL
#define klapan PORTB.2
#define motor_stop {PORTB.1=0;}
#define motor_tormoz {PORTD.4=1;}
#define motor_tormoz_off {PORTD.4=0;}
bit flags_button=0;
volatile unsigned char sek_;
volatile unsigned char timer_button, timer_butt;
volatile unsigned char timer_shou;
volatile unsigned char timer_stop;
volatile unsigned char eep_timer;
volatile unsigned char sek;
volatile unsigned char timer;
volatile unsigned char y,jamp2=0;
volatile unsigned int pwm, start_;
volatile unsigned char pwm_, data0, data1, data2, led_buff[3];
//--------------- 0-9 10 ........... 18 символов
//Символы для LED (0-9, ,-,t,L,A,r,d,b,DP)
flash unsigned char led_table[26]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff,0xbf,0x87,0xC7,0x88,0xAF,0xA1,0x83,0x7F,0x8C,0xC6,0xC1,0x86,0x89,0x8E,0x9C};
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
// [] - t L A r d b Dp P C U E H F град.
//volatile unsigned char y, jamp2=0;
volatile unsigned char start=180;
eeprom unsigned char eep_power, eep_jamp, eep_pwm, eep_sek;
// External Interrupt 0 service routine
interrupt [EXT_INT0] void ext_int0_isr(void) // прерывание для захвата перехода через ноль.
{
// Place your code here Процедура обслуживания внешнего прерывания 0
OUT=OFF;
timer_=start;
}
// Timer 0 overflow interrupt service routine Процедура обслуживания прерывания переполнения таймера 0
interrupt [TIM0_OVF] void timer0_ovf_isr(void) // прерывание для выхода управления тиристорами
{
// Place your code here Разместите свой код здесь
timer_=start;
OUT=ON;
}
// Timer2 overflow interrupt service routine Процедура обслуживания прерывания переполнения Таймера 2
interrupt [TIM2_OVF] void timer2_ovf_isr(void) // прерывание для дисплея
{
// Reinitialize Timer2 value Повторно инициализировать значение Таймера2
TCNT2=0xCB;
if (jamp2==0)
{
PORTD.5=PORTD.6=PORTD.7=0; // выключаем все разряды
switch (y) // общий анод
{
case 0:
PORTC = 0x3F & led_buff[0];
PORTD.0 = 0x40 & led_buff[0];
PORTD.1 = 0x80 & led_buff[0];
Я начинающий! Можете подсказать что значит строка PORTC = 0x3F & led_buff[0]; в этом коде?
#include <mega8.h>
#include <delay.h>
#define ON 1
#define OFF 0
#define timer_ TCNT0
#define timer_tact TCCR0
#define OUT PORTB.0
#define enable PINB.3
#define up PINB.4
#define down PINB.5
#define pwm__ OCR1AL
#define klapan PORTB.2
#define motor_stop {PORTB.1=0;}
#define motor_tormoz {PORTD.4=1;}
#define motor_tormoz_off {PORTD.4=0;}
bit flags_button=0;
volatile unsigned char sek_;
volatile unsigned char timer_button, timer_butt;
volatile unsigned char timer_shou;
volatile unsigned char timer_stop;
volatile unsigned char eep_timer;
volatile unsigned char sek;
volatile unsigned char timer;
volatile unsigned char y,jamp2=0;
volatile unsigned int pwm, start_;
volatile unsigned char pwm_, data0, data1, data2, led_buff[3];
//--------------- 0-9 10 ........... 18 символов
//Символы для LED (0-9, ,-,t,L,A,r,d,b,DP)
flash unsigned char led_table[26]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff,0xbf,0x87,0xC7,0x88,0xAF,0xA1,0x83,0x7F,0x8C,0xC6,0xC1,0x86,0x89,0x8E,0x9C};
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
// [] - t L A r d b Dp P C U E H F град.
//volatile unsigned char y, jamp2=0;
volatile unsigned char start=180;
eeprom unsigned char eep_power, eep_jamp, eep_pwm, eep_sek;
// External Interrupt 0 service routine
interrupt [EXT_INT0] void ext_int0_isr(void) // прерывание для захвата перехода через ноль.
{
// Place your code here Процедура обслуживания внешнего прерывания 0
OUT=OFF;
timer_=start;
}
// Timer 0 overflow interrupt service routine Процедура обслуживания прерывания переполнения таймера 0
interrupt [TIM0_OVF] void timer0_ovf_isr(void) // прерывание для выхода управления тиристорами
{
// Place your code here Разместите свой код здесь
timer_=start;
OUT=ON;
}
// Timer2 overflow interrupt service routine Процедура обслуживания прерывания переполнения Таймера 2
interrupt [TIM2_OVF] void timer2_ovf_isr(void) // прерывание для дисплея
{
// Reinitialize Timer2 value Повторно инициализировать значение Таймера2
TCNT2=0xCB;
if (jamp2==0)
{
PORTD.5=PORTD.6=PORTD.7=0; // выключаем все разряды
switch (y) // общий анод
{
case 0:
PORTC = 0x3F & led_buff[0];
PORTD.0 = 0x40 & led_buff[0];
PORTD.1 = 0x80 & led_buff[0];
Re: Нескольно простых вопросов о программировании AVR на Си.
Вы бы, прежде чем постить, посмотрели бы как люди код вставляют в сообщение.
Re: Нескольно простых вопросов о программировании AVR на Си.
вывод в PORTC значения из нулевого элемента массива led_buff c обнулением двух старших битовelektronic3452 писал(а):что значит строка PORTC = 0x3F & led_buff[0]; в этом коде
Последний раз редактировалось metan Пт сен 13, 2024 09:13:18, всего редактировалось 1 раз.
- Z_h_e
- Собутыльник Кота
- Сообщения: 2708
- Зарегистрирован: Сб май 14, 2011 21:16:04
- Откуда: г. Чайковский
Re: Нескольно простых вопросов о программировании AVR на Си.
Не путайте. В массиве ничего не обнулиться.
- Реклама
Re: Нескольно простых вопросов о программировании AVR на Си.
[uquote="Z_h_e",url="/forum/viewtopic.php?p=4624861#p4624861"]Не путайте.[/uquote]извиняюсь, неверно выразил свою мысль, поправил
-
elektronic3452
- Родился
- Сообщения: 16
- Зарегистрирован: Чт сен 12, 2024 21:34:21
- Откуда: Москва
Re: Нескольно простых вопросов о программировании AVR на Си.
Спасибо!!! "metan" и "Z_h_e"!
-
watchmaker
- Поставщик валерьянки для Кота
- Сообщения: 2183
- Зарегистрирован: Вс ноя 15, 2009 23:13:59
- Откуда: Харьков
- Контактная информация:
Re: Нескольно простых вопросов о программировании AVR на Си.
Немного нубский вопрос, но всё же. ATtiny85. Чип просыпается по внешнему прерыванию на пине PB2, затем сразу же в обработчике прерывания это самое прерывание отключается (PCMSK = 0), а включается обратно (PCMSK = 0b100) существенно позже, перед уходом в спящий режим. Делаю это для того, чтобы постоянно меняющийся уровень на пине (а там летит извне меандр 4 кГц) не вызывал сотни прерываний в секунду при работе основной программы, от них программа тормозит (чип работает на 128 кГц). Контроллер зависает намертво в спящем режиме второй раз за неделю, реагирует только на ресет. Безопасно ли отключать прерывание в обработчике этого же прерывания? И может ли быть такое, что при установке бита в PCMSK прерывание не включается или включается не сразу?
Иногда мой питомец уходит в такую спячку, что разбудить его можно только щелчком по первой ноге...
- Ivanoff-iv
- Друг Кота
- Сообщения: 7077
- Зарегистрирован: Пт ноя 11, 2016 05:48:09
- Откуда: Сердце Пармы
Re: Нескольно простых вопросов о программировании AVR на Си.
Внутри прерывания ничего отключать не надо - т.к. пока ты в прерывании сбрасывается регистр "I" (глобальное разрешение прерываний)
а вот флаг прерывания в конце прерывания очистить наверно не повредит (зависит от решаемой задачи), это исключит повторный вызов прерывания сразу после его завершения если события, вызывающие прерывание, происходили во время прерывания. (флаг прерывания очищается записью в него "1")
а вот флаг прерывания в конце прерывания очистить наверно не повредит (зависит от решаемой задачи), это исключит повторный вызов прерывания сразу после его завершения если события, вызывающие прерывание, происходили во время прерывания. (флаг прерывания очищается записью в него "1")
Для тех, кто не учил магию мир полон физики 
Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
- VNS
- Говорящий с текстолитом
- Сообщения: 1624
- Зарегистрирован: Пт дек 10, 2021 12:48:46
- Откуда: Тюмень
Re: Нескольно простых вопросов о программировании AVR на Си.
[uquote="watchmaker",url="/forum/viewtopic.php?p=4706302#p4706302"]ATtiny85. Чип просыпается по внешнему прерыванию на пине PB2,[/uquote]
Уточните, от какого прерывания просыпается МК, от INT0 или от PCIE0?
вы наверное хотите сказать, что не могли его разбудить два раза за неделю? Дело в том, что для пробуждения МК необходимо удерживать низкий уровень на пине достаточное время, чтобы МК включил питание и запустил тактовый генератор (завершил полностью пробуждение). Если продолжительности уровня на пине не достаточно, то МК может и проснуться, но прерывание не будет сгенерировано. Обратите внимание в даташите какое время необходимо МК для полного пробуждения.
Уточните, от какого прерывания просыпается МК, от INT0 или от PCIE0?
То есть, этот меандр будит ваш МК?Делаю это для того, чтобы постоянно меняющийся уровень на пине (а там летит извне меандр 4 кГц) не вызывал сотни прерываний в секунду
Контроллер в спящем режиме (Power-down) и так всегда «весит», то есть "спит и ничего не делает", экономит энергию…Контроллер зависает намертво в спящем режиме второй раз за неделю,
Re: Нескольно простых вопросов о программировании AVR на Си.
Отключайте безопасно.watchmaker писал(а):Безопасно ли отключать прерывание в обработчике этого же прерывания?
Последний раз редактировалось akl Сб апр 19, 2025 04:34:16, всего редактировалось 1 раз.
-
watchmaker
- Поставщик валерьянки для Кота
- Сообщения: 2183
- Зарегистрирован: Вс ноя 15, 2009 23:13:59
- Откуда: Харьков
- Контактная информация:
Re: Нескольно простых вопросов о программировании AVR на Си.
ISR(PCINT0_vect)Уточните, от какого прерывания просыпается МК, от INT0 или от PCIE0?
Да, МК подключён к выходу пищалки в электронных часах и просыпается от такого сигнала.То есть, этот меандр будит ваш МК?
Виснет так, что не разбудишь даже подачей постоянного уровня на пин, как будто прерывание не включилось при уходе в слип. Если конечно это вообще не аппаратные проблемы типа помех по питанию.Контроллер в спящем режиме (Power-down) и так всегда «весит», то есть "спит и ничего не делает", экономит энергию…вы наверное хотите сказать, что не могли его разбудить два раза за неделю?
Иногда мой питомец уходит в такую спячку, что разбудить его можно только щелчком по первой ноге...
Re: Нескольно простых вопросов о программировании AVR на Си.
[uquote="watchmaker",url="/forum/viewtopic.php?p=4706384#p4706384"]Виснет так, что не разбудишь даже подачей постоянного уровня на пин, как будто прерывание не включилось при уходе в слип. Если конечно это вообще не аппаратные проблемы типа помех по питанию.[/uquote]
На пьезо какое напряжение? Бывает их раскачивают...
На пьезо какое напряжение? Бывает их раскачивают...
-
watchmaker
- Поставщик валерьянки для Кота
- Сообщения: 2183
- Зарегистрирован: Вс ноя 15, 2009 23:13:59
- Откуда: Харьков
- Контактная информация:
Re: Нескольно простых вопросов о программировании AVR на Си.
Пьезо там уже нет, сигнал запуска с часового чипа идёт прямо на МК, а с МК совсем другой сигнал идёт через мосфет на 32 Ом динамик.
Иногда мой питомец уходит в такую спячку, что разбудить его можно только щелчком по первой ноге...
Re: Нескольно простых вопросов о программировании AVR на Си.
Я имею ввиду входное напряжение. И пофигу ваши динамики.
- VNS
- Говорящий с текстолитом
- Сообщения: 1624
- Зарегистрирован: Пт дек 10, 2021 12:48:46
- Откуда: Тюмень
Re: Нескольно простых вопросов о программировании AVR на Си.
[uquote="watchmaker",url="/forum/viewtopic.php?p=4706384#p4706384"]ISR(PCINT0_vect)[/uquote]
Тогда (ИМХО) правильней использовать не регистр PCMSK в вашем случае, а регистр GIMSK (бит PCIE) для разрешения или запрета прерывания по маске пинов, а выбор пина (PCMSK) не трогать. Ну и не забывать при установке (PCIE), сбрасывать бит прерывания (PCIF).
Ну и сформировать достаточный временной потенциал для полного пробуждения МК.
Тогда (ИМХО) правильней использовать не регистр PCMSK в вашем случае, а регистр GIMSK (бит PCIE) для разрешения или запрета прерывания по маске пинов, а выбор пина (PCMSK) не трогать. Ну и не забывать при установке (PCIE), сбрасывать бит прерывания (PCIF).
Ну и сформировать достаточный временной потенциал для полного пробуждения МК.
-
watchmaker
- Поставщик валерьянки для Кота
- Сообщения: 2183
- Зарегистрирован: Вс ноя 15, 2009 23:13:59
- Откуда: Харьков
- Контактная информация:
Re: Нескольно простых вопросов о программировании AVR на Си.
3 В, как и на МК.Я имею ввиду входное напряжение. И пофигу ваши динамики.
Попробую.Тогда (ИМХО) правильней использовать не регистр PCMSK в вашем случае, а регистр GIMSK (бит PCIE) для разрешения или запрета прерывания по маске пинов, а выбор пина (PCMSK) не трогать. Ну и не забывать при установке (PCIE), сбрасывать бит прерывания (PCIF).
Кстати, в даташите написано, что этот флаг сбрасывается записью в него единицы. Это не опечатка, надо писать именно единицу?
Иногда мой питомец уходит в такую спячку, что разбудить его можно только щелчком по первой ноге...
- VNS
- Говорящий с текстолитом
- Сообщения: 1624
- Зарегистрирован: Пт дек 10, 2021 12:48:46
- Откуда: Тюмень
Re: Нескольно простых вопросов о программировании AVR на Си.
[uquote="watchmaker",url="/forum/viewtopic.php?p=4706623#p4706623"]Это не опечатка, надо писать именно единицу?[/uquote]
Не опечатка, да "1".
Не опечатка, да "1".
-
fomkin1912
- Открыл глаза
- Сообщения: 46
- Зарегистрирован: Пт дек 02, 2022 00:37:17
Re: Нескольно простых вопросов о программировании AVR на Си.
Памагите! Вопрос тупой, но все извилины заплел.
Запрограммировал секундомер на Атмеге8 по учебному примеру, и все заработало. Но как?? как он работает???
В счетчике времени (переменная "display") установлена задержка 10мс - это 1/100 секунды (это точно, верьте - я уже на калькуляторе проверял). То есть счетчик увеличивается на единицу каждую сотую секунды, а на индикатор выводятся десятые! Почему???
Вот программа:
// Подключение семисегментных индикаторов к AVR. Динамическая индикация
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
//---------------------------0-----1-----2-----3-----4-----5-----6-----7-----8------9
unsigned char SEGMENTE[] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F};
unsigned char segcounter = 0;
unsigned int display = 0;
// Обработчик прерывания по переполнению таймера 2
ISR(TIMER2_OVF_vect)
{
PORTD = 0xFF; // Гасим все разряды
PORTB = (1 << segcounter); // Выбираем следующий разряд
switch(segcounter)
{
case 0:
PORTD = ~(SEGMENTE[display % 10000 / 1000]); // Раскладываем число на разряды
break;
case 1:
PORTD = ~(SEGMENTE[display % 1000 / 100]);
break;
case 2:
PORTD = ~(SEGMENTE[display % 100 / 10]);
break;
case 3:
PORTD = ~(SEGMENTE[display % 10]);
break;
}
if(segcounter++ > 2) segcounter = 0;
}
// Главная функция
int main(void)
{
DDRB = 0xFF; // Порт B - выход
PORTB = 0x00;
DDRD = 0xFF; // Порт D - выход
PORTD = 0x00;
TCCR2 |= (1 << CS21); // Предделитель на 8
TIMSK |= (1 << TOIE2); // Разрешение прерывания по таймеру 2
sei(); // Глобально разрешаем прерывания
while(1)
{
display++; // Увеличиваем счет от 0 до 9999
if(display > 9999) display = 0;
_delay_ms(10); // Задержка
}
}
Запрограммировал секундомер на Атмеге8 по учебному примеру, и все заработало. Но как?? как он работает???
В счетчике времени (переменная "display") установлена задержка 10мс - это 1/100 секунды (это точно, верьте - я уже на калькуляторе проверял). То есть счетчик увеличивается на единицу каждую сотую секунды, а на индикатор выводятся десятые! Почему???
Вот программа:
// Подключение семисегментных индикаторов к AVR. Динамическая индикация
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
//---------------------------0-----1-----2-----3-----4-----5-----6-----7-----8------9
unsigned char SEGMENTE[] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F};
unsigned char segcounter = 0;
unsigned int display = 0;
// Обработчик прерывания по переполнению таймера 2
ISR(TIMER2_OVF_vect)
{
PORTD = 0xFF; // Гасим все разряды
PORTB = (1 << segcounter); // Выбираем следующий разряд
switch(segcounter)
{
case 0:
PORTD = ~(SEGMENTE[display % 10000 / 1000]); // Раскладываем число на разряды
break;
case 1:
PORTD = ~(SEGMENTE[display % 1000 / 100]);
break;
case 2:
PORTD = ~(SEGMENTE[display % 100 / 10]);
break;
case 3:
PORTD = ~(SEGMENTE[display % 10]);
break;
}
if(segcounter++ > 2) segcounter = 0;
}
// Главная функция
int main(void)
{
DDRB = 0xFF; // Порт B - выход
PORTB = 0x00;
DDRD = 0xFF; // Порт D - выход
PORTD = 0x00;
TCCR2 |= (1 << CS21); // Предделитель на 8
TIMSK |= (1 << TOIE2); // Разрешение прерывания по таймеру 2
sei(); // Глобально разрешаем прерывания
while(1)
{
display++; // Увеличиваем счет от 0 до 9999
if(display > 9999) display = 0;
_delay_ms(10); // Задержка
}
}
Последний раз редактировалось Аlex Чт ноя 06, 2025 16:23:49, всего редактировалось 1 раз.
- Аlex
- Модератор
- Сообщения: 4614
- Зарегистрирован: Чт мар 18, 2010 23:09:57
- Откуда: Планета Земля
- Контактная информация:
Re: Нескольно простых вопросов о программировании AVR на Си.
Выведите, для начала, константу. И посмотрите, что выводится. Если не то, что нужно, - пошаговая отладка спасёт.
И, блин, ну что за форматирование ? Глаз дёргается.
Минута в интернете и всё красиво :
И, блин, ну что за форматирование ? Глаз дёргается.
Минута в интернете и всё красиво :
Спойлер
Код: Выделить всё
// Подключение семисегментных индикаторов к AVR. Динамическая индикация
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
// Массив кодов для семисегментного индикатора (цифры 0-9)
unsigned char SEGMENTE[] = {
0x3F, // 0
0x06, // 1
0x5B, // 2
0x4F, // 3
0x66, // 4
0x6D, // 5
0x7D, // 6
0x07, // 7
0x7F, // 8
0x6F // 9
};
unsigned char segcounter = 0;
unsigned int display = 0;
// Обработчик прерывания по переполнению таймера 2
ISR(TIMER2_OVF_vect)
{
PORTD = 0xFF; // Гасим все разряды
PORTB = (1 << segcounter); // Выбираем следующий разряд
switch(segcounter)
{
case 0:
PORTD = ~(SEGMENTE[display % 10000 / 1000]); // Тысячи
break;
case 1:
PORTD = ~(SEGMENTE[display % 1000 / 100]); // Сотни
break;
case 2:
PORTD = ~(SEGMENTE[display % 100 / 10]); // Десятки
break;
case 3:
PORTD = ~(SEGMENTE[display % 10]); // Единицы
break;
}
if(segcounter++ > 2)
segcounter = 0;
}
// Главная функция
int main(void)
{
// Настройка портов
DDRB = 0xFF; // Порт B - выход (выбор разряда)
PORTB = 0x00;
DDRD = 0xFF; // Порт D - выход (сегменты)
PORTD = 0x00;
// Настройка таймера 2
TCCR2 |= (1 << CS21); // Предделитель на 8
TIMSK |= (1 << TOIE2); // Разрешение прерывания по таймеру 2
sei(); // Глобально разрешаем прерывания
// Основной цикл
while(1)
{
display++; // Увеличиваем счет от 0 до 9999
if(display > 9999)
display = 0;
_delay_ms(10); // Задержка
}
}



