Нескольно простых вопросов о программировании AVR на Си.
Re: Нескольно простых вопросов о программировании AVR на Си.
Спасибо вам. Буду искать причину столь расточительной компиляции
- Реклама
- acckyiboxxx
- Нашел транзистор. Понюхал.
- Сообщения: 182
- Зарегистрирован: Ср янв 25, 2012 07:26:40
Re: Нескольно простых вопросов о программировании AVR на Си.
пишу прошивку для работы с дисплеем на базе контроллера ssd1306 , управляться все будет по интерфейсу i2c , используется аппаратный twi на 16-й меге , все шрифты сгенерил в TheDotFactory-0.1.4 и вставил в свой код следующим образом :
тут вроде все гладко и понятно, привожу листинг функции display_print_char , сразу оговорюсь она еще не дописана так как не хочет компилироваться еще на стадии подготовки данных к отправке на дисплей
при компиляции выдает следующие ошибки :

первая ошибка при двойном клике по ней указывает на определение типа uint16_t в строке
я сначала подумал что компилятор испугался того что я ему подсовываю непонятно что и еще пытаюсь это запихнуть в uint16_t тогда я попытался объяснить ему что все нормально таким вот образом
но это не помогло , что дальше делать - без понятия , есть у кого мысли на этот счет ?
Код: Выделить всё
// сам шрифт
const uint8_t font_wattage[] PROGMEM = {
// @0 '.' (8 pixels wide)
0x00, //
0x00, //
0x00, //
0xFF, // ########
// и так далее, весь шрифт приводить не буду т.к. это овер 500 строк , да и так понятно что тут
};
// здесь список индексов массива со шрифтами указывающий откуда начинается конкретный символ
const uint16_t font_wattage_slice_start[] PROGMEM = {
46 , // zero
184 // one
};
// здесь список индексов массива со шрифтами указывающий где заканчивается конкретный символ
const uint16_t font_wattage_slice_stop[] PROGMEM = {
183 ,// zero
275 // one
};
// здесь список индексов массива со шрифтами указывающий ширину символа
const uint8_t font_wattage_width[] PROGMEM = {
3 ,// zero
2 // one
};
/*
последние 3 массива сформированы так что индексы одинаковы для конкретно взятого символа т.е.
начало символа "ноль" = pgm_read_word(&font_wattage_slice_start[0]);
конец символа "ноль" = pgm_read_word(&font_wattage_slice_stop[0]);
ширина символа "ноль" = pgm_read_word(& font_wattage_width[0]);
*/
Код: Выделить всё
void display_print_char(uint8_t font , uint8_t char_number , uint8_t pos_x , uint8_t pos_y){
display_set_pos(pos_x , pos_y);
switch(font){
case 1: // wattage font
uint16_t read_start = pgm_read_word( &font_wattage_slice_start[ char_number ] ); // начало чтения символа
uint16_t read_stop = pgm_read_word( &font_wattage_slice_stop[ char_number ] ); // конец чтения символа
uint8_t width = pgm_read_byte( &font_wattage_width[ char_number ] ); // получаем ширину символа
uint8_t tmp_buf[ width + 1]; // инициализируем массив размером с ширину символа + 1 байт
tmp_buf[0] = 0x40; // первым делом всегда поясняем дисплею что шлем данные
// запускаем цикл с шагом = width и счетом по положению символа в массиве
for (uint16_t c = read_start ; c <= read_stop ; c += width){
for(uint8_t s = 0 ; s < width ; s++){ // запускаем цикл длиной width для чтения текущей строки
tmp_buf[ s+1 ] = pgm_read_byte(&font_wattage[c + s]);
}
}
break;
}
}

первая ошибка при двойном клике по ней указывает на определение типа uint16_t в строке
Код: Выделить всё
uint16_t read_start = pgm_read_word( &font_wattage_slice_start[ char_number ] ); // начало чтения символаКод: Выделить всё
uint16_t read_start = (uint16_t*) pgm_read_word( &font_wattage_slice_start[ char_number ] ); // начало чтения символа- Реклама
гостевая2
Re: Нескольно простых вопросов о программировании AVR на Си.
Заверните тело под case 1: в фигурные скобки:acckyiboxxx писал(а):первая ошибка при двойном клике по ней указывает на определение типа uint16_t в строке
Код: Выделить всё
switch (font) {
case 1: { // wattage font
[...]
break;
}
}Одновременным нажатием LIGHT и POWER, РП Sangean ATS-909X (ver 1.29) превращается в ATS-909XR! 
- acckyiboxxx
- Нашел транзистор. Понюхал.
- Сообщения: 182
- Зарегистрирован: Ср янв 25, 2012 07:26:40
Re: Нескольно простых вопросов о программировании AVR на Си.
ни за что не догадался-бы , спасибо , помогло 
- c2n
- Сверлит текстолит когтями
- Сообщения: 1193
- Зарегистрирован: Ср июл 25, 2012 21:40:09
- Откуда: Самара
- Контактная информация:
Re: Нескольно простых вопросов о программировании AVR на Си.
Эм. В switsh объявлять переменные - плохой тон.
Есть правило, что все переменные изменяемые в условии - должны быть инициализированы ДО начала условия.
Типа..
char a=0;
Char b=0;
switch (c)
{
case 1:
a=1;
b=2;
break;
case 2:
case 3:
a=10;
b=20;
break;
default:
a=100;
b=500;
break;
}
В этом коде демонстрируется что если некая переменная с =1, то а=1, б=2.
С=2 или 3, то 10 и 20.
В остальных случаях 100 и 500.
Есть правило, что все переменные изменяемые в условии - должны быть инициализированы ДО начала условия.
Типа..
char a=0;
Char b=0;
switch (c)
{
case 1:
a=1;
b=2;
break;
case 2:
case 3:
a=10;
b=20;
break;
default:
a=100;
b=500;
break;
}
В этом коде демонстрируется что если некая переменная с =1, то а=1, б=2.
С=2 или 3, то 10 и 20.
В остальных случаях 100 и 500.
- Реклама
гостеваая 3
Re: Нескольно простых вопросов о программировании AVR на Си.
Я бы сказал, что "огораживание" тела каждого кейса в блок - это хороший тон. Коль переменная нигде кроме как там и не нужна - незачем ей и своим присутствием пространство имён функции поганить.c2n писал(а):Эм. В switsh объявлять переменные - плохой тон.
Одновременным нажатием LIGHT и POWER, РП Sangean ATS-909X (ver 1.29) превращается в ATS-909XR! 
- acckyiboxxx
- Нашел транзистор. Понюхал.
- Сообщения: 182
- Зарегистрирован: Ср янв 25, 2012 07:26:40
Re: Нескольно простых вопросов о программировании AVR на Си.
всем спасибо за мнения. учту а тем временем я похоже снова где-то накосячил причем жестко , инициализирую внешнее прерывание INT1 , пишу обработчик , залил на макетку , прерывание не пашет , засимулил в протеусе так полный хаос увидел :
во-первых инициализировал по падающему фронту а протеус пишет что по нижнему уровню
во-вторых под инициализацию попали каким-то боком INT0 И INT2 (на скрине ниже это видно)
в-третьих при симуляции INT1 срабатывает только 1 раз , далее сколько по кнопкам не тыркай - реакции никакой , при этом на макетке нет даже этого первого срабатывания
думал что криво написал обработчик , вычистил его оставив только задержку на дребезг контактов - ситуация не поменялась
код обработчика приводить не буду так как даже при наличии одного-лишь _delay_ms(20); в нем глюки не исчезают
так-же пробовал грешить на использованные мной указатели , вдруг добрались до GICR , вынес из кода все фрагменты записи по указателю , теперь с ними работает только pgm_read_byte() и pgm_read_word() то-бишь только на чтение , не помогло
и скрин симуляции о котором шла речь выше

понимаю , информации мало , но мб кто-то знает какого типа ошибка могла привести к такому безобразию
ps: компилятор ни варнингов и ошибок не выдает
во-первых инициализировал по падающему фронту а протеус пишет что по нижнему уровню
во-вторых под инициализацию попали каким-то боком INT0 И INT2 (на скрине ниже это видно)
в-третьих при симуляции INT1 срабатывает только 1 раз , далее сколько по кнопкам не тыркай - реакции никакой , при этом на макетке нет даже этого первого срабатывания
думал что криво написал обработчик , вычистил его оставив только задержку на дребезг контактов - ситуация не поменялась
код обработчика приводить не буду так как даже при наличии одного-лишь _delay_ms(20); в нем глюки не исчезают
так-же пробовал грешить на использованные мной указатели , вдруг добрались до GICR , вынес из кода все фрагменты записи по указателю , теперь с ними работает только pgm_read_byte() и pgm_read_word() то-бишь только на чтение , не помогло
Код: Выделить всё
void buttons_interrupt_init(void){
PORTC |= _BV(PC2) | _BV(PC3) | _BV(PC4) | _BV(PC5) | _BV(PC6);
DDRC &= ~( _BV(DDC2) & _BV(DDC3) & _BV(DDC4) & _BV(DDC5) & _BV(DDC6));
DDRD &= ~_BV(DDD3);
PORTD |= _BV(PD3);
buttons_interrupt_change_edge(1);
GICR |= _BV(INT1);
}
void buttons_interrupt_change_edge(uint8_t edge){
cli();
switch(edge){ // ЧЕКАЕМ ЧЕ ПРИЛЕТЕЛО
case 1 : { // ЕСЛИ 1 ТО ОТРАБАТЫВАЕМ ПО СПАДАЮЩЕМУ ФРОНТУ 1->0
MCUCR |= _BV(ISC11);
MCUCR &= ~_BV(ISC10);
}
case 0 : { // ЕСЛИ 0 ТО ПО НАРАСТАЮЩЕМУ ФРОНТУ 0->1
MCUCR |= _BV(ISC10) | _BV(ISC11);
}
default: break;
}
GIFR = (1<<INTF1);
sei();
}

понимаю , информации мало , но мб кто-то знает какого типа ошибка могла привести к такому безобразию
ps: компилятор ни варнингов и ошибок не выдает
Re: Нескольно простых вопросов о программировании AVR на Си.
А вот MISRA C настоятельно рекомендует сужать область видимости переменных до минимума.c2n писал(а):Эм. В switsh объявлять переменные - плохой тон.
Если в switch'е определена ветвь default, то это не имеет смысла. И существует рекомендация всегда определять эту ветвь в switch'ах.c2n писал(а):Есть правило, что все переменные изменяемые в условии - должны быть инициализированы ДО начала условия.
- Из овощей я больше всего люблю пельмени... © Соседский Мальчик
- acckyiboxxx
- Нашел транзистор. Понюхал.
- Сообщения: 182
- Зарегистрирован: Ср янв 25, 2012 07:26:40
Re: Нескольно простых вопросов о программировании AVR на Си.
вот уже вторые сутки не могу победить проблему , создал отдельный проект в котором пытаюсь завести только внешние прерывания и получаю ту-же лажу что описал ранее - протеус показывает только первую сработку прерывания, и как выяснилось программа не заходит в обработчик так как не зажигается светодиод подцепленный к PORTA0
листинг si_1.h
листинг si_1.c
компилить пробовал как в Atmel Studio 6 (Version: 6.2.1563 - Service Pack 2 (Version: AVR8_Toolchain_Version:3.4.5.1522 GCC_VERSION:4.8.1)
так и в eclipse под последней версией winavr - результат симуляции одинаков в обоих случаях (размеры бинарей разые)
листинг si_1.h
Код: Выделить всё
#ifndef _SI_1_H_
#define _SI_1_H_
/************************************************************************/
/* defines */
/************************************************************************/
#define BIT_INVERT(reg, bit) reg ^= (1<<bit)
#define BIT_IS_SET(reg, bit) ((reg & (1<<bit)) != 0)
#define BIT_IS_CLEAR(reg, bit) ((reg & (1<<bit)) == 0)
#define WAIT_FOR_BOUNCE 20 // ЗАДЕРЖКА ДЛЯ ДРЕБЕЗГА КОНТАКТОВ В МИЛЛИСЕКУНДАХ
/************************************************************************/
/* GLOBAL VARIABLES */
/************************************************************************/
/************************************************************************/
/* function declarations */
/************************************************************************/
void buttons_interrupt_init(void);
void buttons_interrupt_change_edge(uint8_t);
#endif
Код: Выделить всё
#define F_CPU 14745600UL
#include <avr/io.h>
#include "si_1.h"
#include "avr/interrupt.h"
#include "util/delay.h"
/************************************************************************/
/* INTERRUPT HANDLERS */
/************************************************************************/
ISR(INT1_vect){ // buttons interrupt
cli(); // ВЫРУБИЛИ ПРЕРЫВАНИЯ ГЛОБАЛЬНО
_delay_ms(WAIT_FOR_BOUNCE); // ОБОЖДАЛИ КОНЦА ДРЕБЕЗГА КОНТАКТОВ
PORTA |= _BV(PA0); // (подключен светодиод для отладки)
sei();
}
/************************************************************************/
/* functions */
/************************************************************************/
void buttons_interrupt_init(void){
PORTC |= _BV(PC2) | _BV(PC3) | _BV(PC4) | _BV(PC5) | _BV(PC6);
DDRC &= ~( _BV(DDC2) & _BV(DDC3) & _BV(DDC4) & _BV(DDC5) & _BV(DDC6));
DDRD &= ~_BV(DDD3);
PORTD |= _BV(PD3);
buttons_interrupt_change_edge(1);
}
void buttons_interrupt_change_edge(uint8_t e){
GICR &= ~_BV(INT1);
switch(e){ // ЧЕКАЕМ ЧЕ ПРИЛЕТЕЛО
case 1 : { // ЕСЛИ 1 ТО ОТРАБАТЫВАЕМ ПО СПАДАЮЩЕМУ ФРОНТУ 1->0
MCUCR |= _BV(ISC11);
MCUCR &= ~_BV(ISC10);
break;
}
case 0 : { // ЕСЛИ 0 ТО ПО НАРАСТАЮЩЕМУ ФРОНТУ 0->1
MCUCR |= _BV(ISC10) | _BV(ISC11);
break;
}
}
GIFR = (1<<INTF1);
GICR |= _BV(INT1);
}
int main(void){
buttons_interrupt_init();
DDRA = 0xFF;
while(1){
}
return 0;
}
так и в eclipse под последней версией winavr - результат симуляции одинаков в обоих случаях (размеры бинарей разые)
- prinv
- Вымогатель припоя
- Сообщения: 677
- Зарегистрирован: Чт янв 20, 2011 09:07:08
- Откуда: Пермь
- Контактная информация:
Re: Нескольно простых вопросов о программировании AVR на Си.
Какой МК используете?
Никакая контра не уйдёт от нас
- acckyiboxxx
- Нашел транзистор. Понюхал.
- Сообщения: 182
- Зарегистрирован: Ср янв 25, 2012 07:26:40
Re: Нескольно простых вопросов о программировании AVR на Си.
atmega16a-auprinv писал(а):Какой МК используете?
макетку питаю от 3.3 вольт , в протеусе в разделе "configure power rails" на vcc так-же выставил 3.3 вольта , кварц на 14.7456Mhz
- prinv
- Вымогатель припоя
- Сообщения: 677
- Зарегистрирован: Чт янв 20, 2011 09:07:08
- Откуда: Пермь
- Контактная информация:
Re: Нескольно простых вопросов о программировании AVR на Си.
Вот эта строка
в buttons_interrupt_init() зачем?
Попробуйте её закомментировать.
В догонку - а INT1 резистором подтянут?
Код: Выделить всё
PORTD |= _BV(PD3);Попробуйте её закомментировать.
В догонку - а INT1 резистором подтянут?
Никакая контра не уйдёт от нас
- ARV
- Ум, честь и совесть. И скромность.
- Сообщения: 18544
- Зарегистрирован: Чт дек 28, 2006 08:19:56
- Откуда: Новочеркасск
- Контактная информация:
Re: Нескольно простых вопросов о программировании AVR на Си.
что бросилось в глаза:
1. #define F_CPU 14745600UL не должно быть в тексте программы!
2. cli(); // ВЫРУБИЛИ ПРЕРЫВАНИЯ ГЛОБАЛЬНО - в обработчике прерываний не нужно
3. _delay_ms(WAIT_FOR_BOUNCE); // ОБОЖДАЛИ КОНЦА ДРЕБЕЗГА КОНТАКТОВ - в обработчике прерываний ОЧЕНЬ ПЛОХО, хотя принципиально допустимо
4. sei(); - в конце обработчика прерываний 100% лишнее
ну и макросы для проверки установки или сброса бита в регистре уже за вас предопределены... но это так, к слову
1. #define F_CPU 14745600UL не должно быть в тексте программы!
2. cli(); // ВЫРУБИЛИ ПРЕРЫВАНИЯ ГЛОБАЛЬНО - в обработчике прерываний не нужно
3. _delay_ms(WAIT_FOR_BOUNCE); // ОБОЖДАЛИ КОНЦА ДРЕБЕЗГА КОНТАКТОВ - в обработчике прерываний ОЧЕНЬ ПЛОХО, хотя принципиально допустимо
4. sei(); - в конце обработчика прерываний 100% лишнее
ну и макросы для проверки установки или сброса бита в регистре уже за вас предопределены... но это так, к слову
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
- prinv
- Вымогатель припоя
- Сообщения: 677
- Зарегистрирован: Чт янв 20, 2011 09:07:08
- Откуда: Пермь
- Контактная информация:
Re: Нескольно простых вопросов о программировании AVR на Си.
замечания по всем 4-м пунктам правильные, но проблема не в них.ARV писал(а):что бросилось в глаза:
Никакая контра не уйдёт от нас
- ARV
- Ум, честь и совесть. И скромность.
- Сообщения: 18544
- Зарегистрирован: Чт дек 28, 2006 08:19:56
- Откуда: Новочеркасск
- Контактная информация:
Re: Нескольно простых вопросов о программировании AVR на Си.
проблема в том, что нет sei() перед главным циклом 
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
- prinv
- Вымогатель припоя
- Сообщения: 677
- Зарегистрирован: Чт янв 20, 2011 09:07:08
- Откуда: Пермь
- Контактная информация:
Re: Нескольно простых вопросов о программировании AVR на Си.
Классика!ARV писал(а):нет sei() перед главным циклом
Никакая контра не уйдёт от нас
- acckyiboxxx
- Нашел транзистор. Понюхал.
- Сообщения: 182
- Зарегистрирован: Ср янв 25, 2012 07:26:40
Re: Нескольно простых вопросов о программировании AVR на Си.
включение внутренней подтяжки лапы к vcc , это в довеско к внешней подтяжке резистором для пущей помехоустойчивости (на этой лапе и висит int1 )
конечная задумка софта такова , юзер нажал любую кнопку , через диоды лапу с прерыванием подтянуло к земле , после чего в обрвботчике прерывания проверяю какая из лап portc2 - portc6 в нуле , выставляю задачу главному циклу + либо в прерывании либо в главном цикле меняю прерывание по падающему фронту на прерывание по нарастающему , это для того что-бы долго не висеть в обработчике INT1_vect и иметь возможность работать с другими прерываниями пока юзер удерживает кнопку
так вот реализация этой задачи встала уже на том этапе что я не попадаю в обработчик по неведомым мне причинам
конечная задумка софта такова , юзер нажал любую кнопку , через диоды лапу с прерыванием подтянуло к земле , после чего в обрвботчике прерывания проверяю какая из лап portc2 - portc6 в нуле , выставляю задачу главному циклу + либо в прерывании либо в главном цикле меняю прерывание по падающему фронту на прерывание по нарастающему , это для того что-бы долго не висеть в обработчике INT1_vect и иметь возможность работать с другими прерываниями пока юзер удерживает кнопку
так вот реализация этой задачи встала уже на том этапе что я не попадаю в обработчик по неведомым мне причинам
компилятор материт меня когда этого нет, а в студии я не нашел где ставить частоту для проекта , в этом плане eclipse юзабельнее , там интуитивно понятно где такая настройка , посему я решил для студии не заморачиваться ибо стандарт допускает такое и влепить частоту прямо в код1. #define F_CPU 14745600UL не должно быть в тексте программы!
это на случай конфликта прерываний , дабы если сработает прерывание с приоритетом выше чем int1 оно ждало пока я выйду из обработчика int12. cli(); // ВЫРУБИЛИ ПРЕРЫВАНИЯ ГЛОБАЛЬНО - в обработчике прерываний не нужно
4. sei(); - в конце обработчика прерываний 100% лишнее
не увидел разницы между ожиданием конца дребезга внутри и вне прерывания , поэтому решил ждать внутри3. _delay_ms(WAIT_FOR_BOUNCE); // ОБОЖДАЛИ КОНЦА ДРЕБЕЗГА КОНТАКТОВ - в обработчике прерываний ОЧЕНЬ ПЛОХО, хотя принципиально допустимо
- acckyiboxxx
- Нашел транзистор. Понюхал.
- Сообщения: 182
- Зарегистрирован: Ср янв 25, 2012 07:26:40
Re: Нескольно простых вопросов о программировании AVR на Си.
твою-ж кошку , вот я слепень, и в большом проекте сам закоментил sei зачем-то , всем спасибо за помощь, пойду дальше бороться со своей тупостью
- prinv
- Вымогатель припоя
- Сообщения: 677
- Зарегистрирован: Чт янв 20, 2011 09:07:08
- Откуда: Пермь
- Контактная информация:
Re: Нескольно простых вопросов о программировании AVR на Си.
Компилятор сам это делаетacckyiboxxx писал(а):это на случай конфликта прерываний , дабы если сработает прерывание с приоритетом выше чем int1 оно ждало пока я выйду из обработчика int1
А прерывание необходимо завершать как можно быстрее.
Подняли какой-нибудь флаг сработки прерывания и на выход.
Никакая контра не уйдёт от нас
- ARV
- Ум, честь и совесть. И скромность.
- Сообщения: 18544
- Зарегистрирован: Чт дек 28, 2006 08:19:56
- Откуда: Новочеркасск
- Контактная информация:
Re: Нескольно простых вопросов о программировании AVR на Си.
acckyiboxxx писал(а):это на случай конфликта прерываний , дабы если сработает прерывание с приоритетом выше чем int1 оно ждало пока я выйду из обработчика int1
это делает не компилятор, а архитектура AVR: без специальных усилий программиста на время работы любого обработчика прерываний все прочие прерывания запрещены. приоритет обработки определяет лишь очередность обслуживания при одновременном наступлении событий, но не возможность прерывать менее приоритетный обработчик более приоритетным.prinv писал(а):Компилятор сам это делает
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!