Нескольно простых вопросов о программировании AVR на Си.
- WiseLord
- Друг Кота
- Сообщения: 4905
- Зарегистрирован: Чт апр 11, 2013 11:19:59
- Откуда: Минск
- Контактная информация:
Re: Нескольно простых вопросов о программировании AVR на Си.
Вот, гляньте на этот код. Как минимум, в Proteus всё работает. Правда, нет защиты от дребезга при отпускании кнопки, но, возможно, она и не нужна при отпускании.
- Вложения
-
- buttons.7z
- (12.51 КБ) 269 скачиваний
Re: Нескольно простых вопросов о программировании AVR на Си.
В комментарии?
Код: Выделить всё
//PORTB=_BV(0); //включаем лампочкуRe: Нескольно простых вопросов о программировании AVR на Си.
Для WiseLord Спасибо огромное за код, из hex заработал на макете. буду изучать код, смотреть где накосячил
Для ks0 По моей логике да. Изначально была команда, но подумав я её исключил, т.к. команда на установку этого бита была подана в пред идущем условии, и других команд на отмену не поступало, так что просто сбрасываем флаг и счетчик. Или я чего не правильно понимаю? Я ж тока тока познакомился с C++
Для ks0 По моей логике да. Изначально была команда, но подумав я её исключил, т.к. команда на установку этого бита была подана в пред идущем условии, и других команд на отмену не поступало, так что просто сбрасываем флаг и счетчик. Или я чего не правильно понимаю? Я ж тока тока познакомился с C++
-
Mikhail
- Родился
- Сообщения: 9
- Зарегистрирован: Пт май 04, 2007 22:32:16
- Откуда: Великий Новгород
- Контактная информация:
Re: Нескольно простых вопросов о программировании AVR на Си.
pcb писал(а):лови друх
http://www.c-cpp.ru/books/inicializaciya-massiva
лень писать, поэтому только так
Чето не понимаю. Сделал все как там написано, все равно ругается.
Re: Нескольно простых вопросов о программировании AVR на Си.
Прошу совета, уже голову сломал...
Контроллер упорно не желает выходить из прерывания - преверяю условие внутри функции прерывания, при его выполнении хочу выйти из функции - условие выполняется, контроллер выполняет действия по условию, но из прерывания не выходит, продолжает выполнять функцию обработки до конца.
Вот код функции обработки прерывания:
Контроллер упорно не желает выходить из прерывания - преверяю условие внутри функции прерывания, при его выполнении хочу выйти из функции - условие выполняется, контроллер выполняет действия по условию, но из прерывания не выходит, продолжает выполнять функцию обработки до конца.
Вот код функции обработки прерывания:
Код: Выделить всё
ISR(INT0_vect) // Внешнее прерывания по появлению сигнала
{
CTR=0; ERR=0; TW=0; HS=0; k=0;
uint8_t n=0;
while (n<50) //цикл ожидания сигнала
{
/*измеряем длительность импульса*/
CTR=0;
while (!(PINB&(1<<PB1))) //пока сигнал 0 меряем длительность сигнала
{
_delay_ms(100); //делаем задержку
CTR++;
if (CTR>=30) //если сигнал длинный
{
n=49;
break; //переходи на включение автомата
}
}
if ((CTR>=1) && (CTR<30)) //если сигнал короткий
{
k++; //увеличиваем период счетчик количества сигналов на 1
n=0; // обнуляем период ожидания нажатия сигнала
if (k>=LOS) // если уже получено 3 сигнала
{
/* ручное включение */
PORTB|=(1<<3); //вкл индикатора
PORTB&=~(1<<4); //0 на порт РВ4
delay_s(MLt);
PORTB|=(1<<4);
PORTB &= ~_BV(PB3);
return; //reti(); //выходим из прерывания
}
}
_delay_ms(100);
n++;
}
for(n=0; n<100; n++){
PORTB^=(1<<PB3);
_delay_ms(150);
}
}- slavokhire5
- Прорезались зубы
- Сообщения: 202
- Зарегистрирован: Пн сен 26, 2011 13:48:25
- Откуда: Харьков
Re: Нескольно простых вопросов о программировании AVR на Си.
itak, прочтите раздел Manually defined ISRs отсюда http://www.nongnu.org/avr-libc/user-man ... rupts.html
возможно поможет
возможно поможет
Осилит дорогу идущий
--------------------------
Пишу на Си за еду
--------------------------
Пишу на Си за еду
Re: Нескольно простых вопросов о программировании AVR на Си.
Прошу совета, есть такой код, обработки индикатора и ультразвукового датчика HC-SR04, все работает, но в конце кода, в цикле присутствует "_delay_ms(60);", из-за чего происходит мерцание индикатора, без задержки не вариант!
Как это обойти? Сильно не пинайте, только учусь)
Код: Выделить всё
#define F_CPU 8000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
volatile long avg = 0;
volatile unsigned char up = 0;
volatile uint32_t running = 0;
volatile uint32_t timercounter =0;
// Прерывание INT1, для определения изменений высокого/низкого уровня напряжения, to detect high/low voltage changes
ISR(TIMER0_OVF_vect)
{
if (up) {
timercounter++;
}
}
void dig_out(int num); // Объявление функции вывода на индикатор
void send_trigger() //Функция работы с триггером, посылает кратковременный импульс 10us
{
PORTD = 0x00;
//_delay_us(5);
PORTD = 0xf0;
running = 1;
_delay_us(10);
PORTD = 0x00;
}
SIGNAL(INT1_vect){
if(running){ //прерывания разрешаются, только когда датчик запущен
if (up == 0) { // voltage rise, start time measurement
up = 1;
timercounter = 0;
TCCR0 |= (0 << CS02)|(0 << CS01)|(1 << CS00); // Start/initialize timer with prescalar 0
TCNT0 = 0; // Initialize Counter
} else { // voltage drop, stop time measurement
up = 0;
avg = (timercounter*32+TCNT0)/58;// divide by 58 to get distance in cm
running = 0;
}
}
}
void dig_out(int num) // Функция для вывода на индикатор 4-х разрядов
{
unsigned char i = 0; // Переменная счетчика
unsigned char raz = 1; // Номер разряда
unsigned char dig_num[] = {
0x3f, //0
0x06, //1
0x5b, //2
0x4f, //3
0x66, //4
0x6d, //5
0x7d, //6
0x07, //7
0x7f, //8
0x6f}; // Коды цифр для индикатора с общим катодом
unsigned char dig[] = {0, 0, 0, 0}; // Массив для значения разряда
if(num < 10) // Для заполнения нулями левых разрядов
{
dig[0] =0;
dig[1] =0;
dig[2] =0;
}
if(num < 100) // Для заполнения нулями левых разрядов
{
dig[0] =0;
dig[1] =0;
}
if(num < 1000) // Для заполнения нулями левых разрядов
{
dig[0] =0;
}
while(num > 999) // Получение количества тысяч
{
dig[0]++;
num -= 1000;
}
while(num > 99) // Получение количества сотен
{
dig[1]++;
num -= 100;
}
while(num > 9) // Получение числа десятков
{
dig[2]++;
num -= 10;
}
dig[3] = num; // Получения количества единиц
while(raz <= 0x10) // Крутимся пока не заполним все 4 разряда
{
PORTA = raz; // Выбираем разряд
PORTC = dig_num[dig[i]]; // Выводим цифру
raz = raz<<1; // Сдвигаемся на следующий разряд
i++; // Увеличиваем индекс следующей цифры
_delay_ms(1); // Задержка 1 мс
}
}
int main(void)
{
DDRA = 0x0F; // Настройка портов
DDRC = 0xFF; // для работы с индикатором Порт A для разрядов, Порт C для цифр
DDRD = 0xf0; //PD4 вход ECHO, PD5 выход на триггер
PORTD = 0x00;
MCUCR |= (0 << ISC11) | (1 << ISC10); // enable interrupt on any(rising/droping) edge
GICR |= (1 << INT1); //Turns on INT1
TIMSK |= (1 << TOIE0); // enable timer interrupt
sei(); // Разрешение прерываний
while(1)
{
dig_out(avg); //Постоянно вызываем функцию вывода текущего числа
if(running == 0) {
_delay_ms(60);
send_trigger();
}
}
}
Re: Нескольно простых вопросов о программировании AVR на Си.
slavokhire5 писал(а):itak, прочтите раздел Manually defined ISRs отсюда http://www.nongnu.org/avr-libc/user-man ... rupts.html
возможно поможет
Спасибо, пробовал отсюда оператор reti() вместо return - не помогает... Странно, все это...
- WiseLord
- Друг Кота
- Сообщения: 4905
- Зарегистрирован: Чт апр 11, 2013 11:19:59
- Откуда: Минск
- Контактная информация:
Re: Нескольно простых вопросов о программировании AVR на Си.
itak: это где вы такому научились - циклы, стомиллисекундные задержки - и всё это внутри прерывания? Прерывание должно выполняться максимально возможно быстро.
-=eagle=-: Вызывайте dig_out() по аппаратному таймеру, а не в цикле main(). Дополнительно, для оптимизации кода не создавайте массив цифр каждый раз в этой функции, объявите его один раз как static. Или даже const static, так как содержимое его не изменяется.
-=eagle=-: Вызывайте dig_out() по аппаратному таймеру, а не в цикле main(). Дополнительно, для оптимизации кода не создавайте массив цифр каждый раз в этой функции, объявите его один раз как static. Или даже const static, так как содержимое его не изменяется.
Re: Нескольно простых вопросов о программировании AVR на Си.
WiseLord: - спасибо, направление, подумаю как сделать по другому.
РS в проекте контроллер ничего не делает (спит) до наступления события. Задержки минутные. Интервалы между событиями часы. В Proteus программа работает....
я только учусь (это мой второй проект).
РS в проекте контроллер ничего не делает (спит) до наступления события. Задержки минутные. Интервалы между событиями часы. В Proteus программа работает....
я только учусь (это мой второй проект).
Re: Нескольно простых вопросов о программировании AVR на Си.
WiseLord писал(а):
-=eagle=-: Вызывайте dig_out() по аппаратному таймеру, а не в цикле main(). Дополнительно, для оптимизации кода не создавайте массив цифр каждый раз в этой функции, объявите его один раз как static. Или даже const static, так как содержимое его не изменяется.
Сделал по таймеру сравнения, все заработало, но не совсем корректно, показания с датчика чудят при определенный настройках, а когда не чудит. индикатор мерцает, никак не совместить эти моменты, не пойму как грамотно его настроить
Спойлер
Код: Выделить всё
#define F_CPU 8000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
volatile long avg = 0;
volatile long result = 1234;
volatile unsigned char up = 0;
volatile uint32_t running = 0;
volatile uint32_t timercounter =0;
// Прерывание INT1, для определения изменений высокого/низкого уровня напряжения, to detect high/low voltage changes
ISR(TIMER0_OVF_vect)
{
if (up) {
timercounter++;
}
}
void dig_out(int num); // Объявление функции вывода на индикатор
void send_trigger() //Функция работы с триггером, посылает кратковременный импульс 10us
{
PORTD = 0x00;
//_delay_us(5);
PORTD = 0xf0;
running = 1;
_delay_us(10);
PORTD = 0x00;
}
SIGNAL(INT1_vect){
if(running){ //прерывания разрешаются, только когда датчик запущен
if (up == 0) { // voltage rise, start time measurement
up = 1;
timercounter = 0;
TCCR0 |= (0 << CS02)|(0 << CS01)|(1 << CS00); // Start/initialize timer with prescalar 0
TCNT0 = 0; // Initialize Counter
} else { // voltage drop, stop time measurement
up = 0;
avg = (timercounter*32+TCNT0)/58;// divide by 58 to get distance in cm
running = 0;
}
}
}
/*******************************************/
ISR (TIMER1_COMPA_vect) // Обработчик прерывания по совпадению таймера 1
{
dig_out(avg); //Постоянно вызываем функцию вывода текущего числа
TCNT1H=0x00; // Сброс регистра
TCNT1L=0x00; // счета
}
void dig_out(int num) // Функция для вывода на индикатор 4-х разрядов
{
unsigned char i = 0; // Переменная счетчика
unsigned char raz = 1; // Номер разряда
unsigned char dig_num[] = {
0x3f, //0
0x06, //1
0x5b, //2
0x4f, //3
0x66, //4
0x6d, //5
0x7d, //6
0x07, //7
0x7f, //8
0x6f}; // Коды цифр для индикатора с общим катодом
unsigned char dig[] = {0, 0, 0, 0}; // Массив для значения разряда
if(num < 10) // Для заполнения нулями левых разрядов
{
dig[0] =0;
dig[1] =0;
dig[2] =0;
}
if(num < 100) // Для заполнения нулями левых разрядов
{
dig[0] =0;
dig[1] =0;
}
if(num < 1000) // Для заполнения нулями левых разрядов
{
dig[0] =0;
}
while(num > 999) // Получение количества тысяч
{
dig[0]++;
num -= 1000;
}
while(num > 99) // Получение количества сотен
{
dig[1]++;
num -= 100;
}
while(num > 9) // Получение числа десятков
{
dig[2]++;
num -= 10;
}
dig[3] = num; // Получения количества единиц
while(raz <= 0x10) // Крутимся пока не заполним все 4 разряда
{
PORTA = raz; // Выбираем разряд
PORTC = dig_num[dig[i]]; // Выводим цифру
raz = raz<<1; // Сдвигаемся на следующий разряд
i++; // Увеличиваем индекс следующей цифры
_delay_ms(1); // Задержка 1 мс
}
}
int main(void)
{
DDRA = 0x0F; // Настройка портов
DDRC = 0xFF; // для работы с индикатором Порт A для разрядов, Порт C для цифр
DDRD = 0xF0; //PD4 вход ECHO, PD5 выход на триггер
PORTD = 0x00;
TCCR1A=0x00; // Настройка таймера
TCCR1B = (0 << CS12)|(0 << CS11)|(1 << CS10);
TCNT1H=0x00;
TCNT1L=0x00;
OCR1AH=0x04;
OCR1AL=0x05;
MCUCR |= (0 << ISC11) | (1 << ISC10); // enable interrupt on any(rising/droping) edge
GICR |= (1 << INT1); //Turns on INT1
TIMSK |= (1 << TOIE0)|(1 << OCIE1A); // enable timer interrupt
sei(); // Разрешение прерываний
while(1)
{
if(running == 0) {
_delay_ms(60);
send_trigger();
}
}
}
- baron_P
- Нашел транзистор. Понюхал.
- Сообщения: 183
- Зарегистрирован: Вт сен 14, 2010 23:07:10
- Откуда: Ростов
Re: Нескольно простых вопросов о программировании AVR на Си.
Есть проблема с таким кодом:
Это я пытаюсь считать 8-бит данных через аппаратный USART контроллера Atmega8 и выдать их на порт Б. Вроде как логика простая: включаю прерывание по окончанию приема, считываю данные из регистра UDR, пока флаг окончания приема не сбросится, передаю данные в другую переменную и вывожу ее на порт. Но не работает. На выводах порта какая-то чушь. Проверяю в Протеусе, тот при этом выдает сообщение RX Frame Error. Кажется, я туплю в понимании методики приема. Подскажите. куда копать?
Спойлер
Код: Выделить всё
#include <avr/io.h>
#include <avr/interrupt.h>
#define F_CPU 8000000UL
volatile unsigned char input_bits; //буфер команды
unsigned char control_bits; //команда
void main(void)
{
//инициализация UART
//удвоение скорости обмена отключено, мультипроцессорный обмен отключен
UCSRA &= ~((1 << U2X) | (1 << MPCM));
//разрешение прерывания по завершению приема, работы порта PD0 на прием
UCSRB |= (1 << RXCIE) | (1 << RXEN);
//запись в UCSRC, асинхронный режим, контроль четности отключен,
//один стоп-бит, 8-разрядное слово
UCSRC |= (1 << URSEL) | (1 << UCSZ1) | (1 << UCSZ0);
//скорость передачи 9600 bps по формуле fck/(16*(speed+1))
UBRRL = 51;
//инициализация выходов
//выхода индикации
DDRB |= 0xFF;
sei();
while(1)
{
control_bits = input_bits;
//индикация команды
PORTB = control_bits;
};
}
//вектор прерывания по окончанию приема байта
ISR(USART_RXC_vect)
{
while (UCSRA & (1 << RXC))
input_bits = UDR;
}Это я пытаюсь считать 8-бит данных через аппаратный USART контроллера Atmega8 и выдать их на порт Б. Вроде как логика простая: включаю прерывание по окончанию приема, считываю данные из регистра UDR, пока флаг окончания приема не сбросится, передаю данные в другую переменную и вывожу ее на порт. Но не работает. На выводах порта какая-то чушь. Проверяю в Протеусе, тот при этом выдает сообщение RX Frame Error. Кажется, я туплю в понимании методики приема. Подскажите. куда копать?
We do what we must because we can (c) GLaDOS
- ARV
- Ум, честь и совесть. И скромность.
- Сообщения: 18544
- Зарегистрирован: Чт дек 28, 2006 08:19:56
- Откуда: Новочеркасск
- Контактная информация:
Re: Нескольно простых вопросов о программировании AVR на Си.
не понятно, нафига все эти переменные и прерывание, когда вы можете просто делать в главном цикле
Код: Выделить всё
while(UCSRA & _BV(RXC)) PORTB = UDR;если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
- baron_P
- Нашел транзистор. Понюхал.
- Сообщения: 183
- Зарегистрирован: Вт сен 14, 2010 23:07:10
- Откуда: Ростов
Re: Нескольно простых вопросов о программировании AVR на Си.
С прерыванием оно как-то красивше. Получили пакет, тут же засунули его в переменную, которую можно потом обработать как душе угодно. Всегда свежие данные есть. В вашем случае данные получаем только один раз за рабочий цикл программы, независимо от того, сколько раз они обновились. Если просто индицировать, оно вроде как и рационально, но я потом планирую еще с этими данными работать.
Вопрос не в этом. Должно же работать и с прерыванием. А оно почему то никак.
Вопрос не в этом. Должно же работать и с прерыванием. А оно почему то никак.
We do what we must because we can (c) GLaDOS
Re: Нескольно простых вопросов о программировании AVR на Си.
А че там за ожидание в прерывании? Обработчик же и так при наступлении события вызывается?
- baron_P
- Нашел транзистор. Понюхал.
- Сообщения: 183
- Зарегистрирован: Вт сен 14, 2010 23:07:10
- Откуда: Ростов
Re: Нескольно простых вопросов о программировании AVR на Си.
В прерывании ожидание сброса флага RXC. В интернетах пишут, что он может не сбросится после первого чтения из UDR, потому читаем до победного, пока не сбросится. Сегодня ковыряться некогда было, завтра попробую без прерываний самый простой вариант, но, кажется, дело не в том.
We do what we must because we can (c) GLaDOS
- baron_P
- Нашел транзистор. Понюхал.
- Сообщения: 183
- Зарегистрирован: Вт сен 14, 2010 23:07:10
- Откуда: Ростов
Re: Нескольно простых вопросов о программировании AVR на Си.
Такой появился вопрос. Если у меня постоянно на вход UART приходят пакеты, то как определяется, где начало, где конец? На картинке пример. Когда приходят нули, все понятно. А когда не ноль, то за стоп/старт-биты может быть принято любое последовательное сочетание 1 и 0. Как этот вопрос разрешается при использовании аппаратного асинхронного UART для пары котнроллеров (передатчик-приемник)?

We do what we must because we can (c) GLaDOS
Re: Нескольно простых вопросов о программировании AVR на Си.
Стоп-бит фиксируется не по любому переходу из низкого в высокий. Получив стартовый бит, автомат USARTа отмеривает время, необходимое для передачи заданного количества бит, включая стартовый, на заданной скорости, после чего проверяет состояние RxD . Если высокий, байт считается принятым, аппарат готов к приему следующего. Если низкий - FRAME ERROR . Поэтому важно, чтобы приемник UART был настроен в соответствии с передаваемыми данными : число бит ( инф. и стоповых ), скорость передачи. Иначе - FRAME ERROR, если его игнорировать, читаем абракадабру.
- baron_P
- Нашел транзистор. Понюхал.
- Сообщения: 183
- Зарегистрирован: Вт сен 14, 2010 23:07:10
- Откуда: Ростов
Re: Нескольно простых вопросов о программировании AVR на Си.
Со стопом понятно. Но старт-битом ведь считается любой переход от 1 к 0. Контроллеры не синхронизированны по частоте, и в какой момент (имеется в виду начальный, при включении питания контроллеров) начнется передача на передатчике и прием на приемнике (жуть какая) не ясно. Т.е. приемник может включиться на прием чуть позже и считать переход от второго бита на третий как переход стоп-старт (см. рисунок выше). Или это как-то не так работает?
We do what we must because we can (c) GLaDOS
- Аlex
- Модератор
- Сообщения: 4614
- Зарегистрирован: Чт мар 18, 2010 23:09:57
- Откуда: Планета Земля
- Контактная информация:
Re: Нескольно простых вопросов о программировании AVR на Си.
Это как ?baron_P писал(а):Т.е. приемник может включиться на прием чуть позже
Он включится ровно тогда, когда ему об этом скажут. Как Вы только настроили приёмник, он сразу готов принимать.
