CodeVision AVR в вопросах и ответах

Обсуждаем контроллеры компании Atmel.
Ответить
Говорящий с текстолитом
Аватара пользователя
Сообщения: 1525
Зарегистрирован: Чт июн 10, 2010 20:11:19

Сообщение COKPOWEHEU »

Там вроде проблема даже с прямым обращением к массиву.
Как ведет себя программа, если задать массив фиксированной длины uint8_t first[9];
Или если обращаться как к указателю
uint8_t *first = ...
*(first+5) = 1;
Реклама
Мучитель микросхем
Сообщения: 469
Зарегистрирован: Вс авг 30, 2015 03:52:59

Сообщение Pnjom-Penb »

COKPOWEHEU писал(а):Там вроде проблема даже с прямым обращением к массиву.
Как ведет себя программа, если задать массив фиксированной длины uint8_t first[9];
Или если обращаться как к указателю
uint8_t *first = ...
*(first+5) = 1;
Вечером воскресного дня как-то не въехал - в чем проблема-то? :shock:
Реклама
Говорящий с текстолитом
Аватара пользователя
Сообщения: 1525
Зарегистрирован: Чт июн 10, 2010 20:11:19

Сообщение COKPOWEHEU »

Код: Выделить всё

D2printf("first = ");
    for(i=0;i<9;i++)   
    {     
        first[i] = i;
        D2printf("%u ", first[i]);
    }   
    D2printf("\n");
Даже такая простая операция выдаёт: first = 0 1 2 3 0 0 0 0 0
Я вот про эту цитату, стоит разобраться где здесь баг.
Вымогатель припоя
Аватара пользователя
Сообщения: 601
Зарегистрирован: Пт фев 13, 2009 20:58:13
Откуда: Донецк

Сообщение DataLife »

Доброго времени суток.
Где-то закрался косяк с скромный код программы-вольтметра (вернее измерителя АЦП) с выводом значения на LCD 16x2 экранчик.

Отдельно измеритель код АЦП работает, что показывает не одно моё устройство.
Отдельно вывод динамических данных на дисплей тоже работает. Проверил...
Всё это вместе работает более чем странно:
Значения АЦП должны быть 0...1024, но независимо от того, на GND или на Vcc я подкину ногу ADC0, на экране данные от 100 до 9800 (примерно) :shock: И скачут как им хочется.

МК ATmega8A.

Может кто ткнёт носом в ошибку?
Спойлер/****************
AVR Core Clock frequency: 1,000000 MHz
*****************/

#include <mega8.h>
#include <lcd.h>
#include <delay.h>
#include <stdio.h> // библиотека для преобразования переменных в строки

#asm
.equ __lcd_port=0x12; PORTD /* ЖКИ дисплей подключили к порту I/O D */
#endasm

// Обьявзяем переменные
char lcd_buffer[20]; // создается буфер (масив) для символов, выводимых на дисплей
unsigned int res; // переменная для хранения хначения АЦП

//Функция измерения АЦП

unsigned int ADC_result(void)
{
ADCSRA = 0b10000100; // - предделитель на 16, прерывания запрещены, ADC включён
ADMUX = 0b11000000; // - 2.56VCC , ACD0, ADLAR off
delay_us(30); //задержка для стабилизации
ADCSRA |= 0x40; //начинаем измерение
while((ADCSRA & 0x10)==0); //Ждём флаг окончания измерения
ADCSRA |=0x10;
return ADCW; //Возвращаем функции значение регистра ADCW
}

void main(void) /* Основная функция "main", с которой начинается выполнение всей программой процедуры */
{

lcd_init(16);
lcd_gotoxy(2,0);
lcd_putsf("Digital ADC");
lcd_gotoxy(1,1);
lcd_putsf("CodeVision AVR");
delay_ms(1000);
lcd_clear();

while(1){
res = ADC_result(); //значение измерения АЦП присваеваем переменной RES
lcd_gotoxy(0,0);
sprintf(lcd_buffer, "ADC = %i", res); // преобразуем переменные в строки
lcd_puts(lcd_buffer); // выводим строку на дисплей
delay_ms(500);
lcd_clear(); // первая ошибка
}
}
UPD1: если добавить очистку дисплея после каждого преобразования, то данные на дисплее станут более правдопадобными. При подключении на "землю" показывает 105...90, а при подключении на +5 показывает ~900.
Но тем не менее врёт...
Только те, кто предпринимают абсурдные попытки, смогут достичь невозможного.
Реклама
Эиком - электронные компоненты и радиодетали
Опытный кот
Сообщения: 804
Зарегистрирован: Чт мар 12, 2009 16:31:05

Сообщение Vov123 »

DataLife писал(а): если добавить очистку дисплея после каждого преобразования, то данные на дисплее станут более правдопадобными.
новые данные накладываются на старые
Реклама
Вымогатель припоя
Аватара пользователя
Сообщения: 601
Зарегистрирован: Пт фев 13, 2009 20:58:13
Откуда: Донецк

Сообщение DataLife »

Вопрос решил.
Ещё всё досконально проверю, но вышло так: скорее всего нужно было подтянуть AREF на землю через конденсатор. На моей версии плате это я не предусмотрел, зато предусмотрел LC фильтр для AVCC. Перенастроил АЦП на эту ногу, а не на внутренние 2.56В, и всё стало показывать верно.

Учиться... учиться ... и ещё раз учиться :)

Как бы то ни было, всем спасибо :)
Только те, кто предпринимают абсурдные попытки, смогут достичь невозможного.
Реклама
gis
Родился
Сообщения: 16
Зарегистрирован: Пт ноя 07, 2014 20:34:56

Сообщение gis »

Здравствуйте, у меня следующая проблема. С ATmega8 мне необходимо управлять драйвером шаговика по step/dir. Кусок кода ниже работает, но если заявить переменную Apos в eeprom, то ничего не работает (драйвер включает обмотки хаотично, LCD- экранчик не инициализируется). Кажется, что контроллер не стартует. Не могу понять как это может быть связано с тем, для какой памяти я заявляю переменную.

Код: Выделить всё

eeprom int Zpos= 10000;    //заданное положение
int Apos=0;                       //актуальное положение

// Timer 0 overflow interrupt service routine
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
TCNT0=0x83;
if (Apos==Zpos)
{MOTOR_ENABLE=0;}
else
{
if (Apos<Zpos)
{
MOTOR_DIRECTION=1;
MOTOR_ENABLE=1;
MOTOR_STEP=1;
delay_us(5) ;
MOTOR_STEP=0;
Apos++;
}
else
{
MOTOR_DIRECTION=0;
MOTOR_ENABLE=1;
MOTOR_STEP=1;
delay_us(5) ;
MOTOR_STEP=0;
Apos--;
}
};
}
Друг Кота
Аватара пользователя
Сообщения: 4905
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск

Сообщение WiseLord »

А не жалко EEPROM так насиловать?
Он, во-первых, медленный (запись вполне может не успевать в прерывании выполниться), во-вторых, ограничен в количестве циклов перезаписи. Несколько минут работы с eeprom Apos++ в прерывании - и МК можно выбрасывать на мусорку. Ну или забыть про дальнейшее использование EEPROM в нём.
Контактная информация:
gis
Родился
Сообщения: 16
Зарегистрирован: Пт ноя 07, 2014 20:34:56

Сообщение gis »

Спасибо за разъяснение. Просто я хотел чтобы он позицию помнил после выключения.
Друг Кота
Аватара пользователя
Сообщения: 4905
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск

Сообщение WiseLord »

Ну так и запоминать надо при выключении, восстанавливая при включении значение.
А сотню раз в секунду флеш писать - это издевательство над МК.
Контактная информация:
gis
Родился
Сообщения: 16
Зарегистрирован: Пт ноя 07, 2014 20:34:56

Сообщение gis »

А можно сделать так чтобы контроллер понял, что его выключают. Или придется делать кнопку, по которой он будет копировал переменную в еепром ?
Друг Кота
Аватара пользователя
Сообщения: 4905
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск

Сообщение WiseLord »

Проще кнопкой. Но можно и с помощью АЦП или входа INT0/1. Главное, чтобы питание МК снижалось медленнее (за счёт тех же конденсаторов по питанию) чем напряжение на входе АЦП или уровень на INT0/1 (резистивный делитель, отделённый диодом от основного питания). Тогда можно отловить факт отключения и сохранить в EEPROM значение ещё до того, как питание МК окончательно пропадёт.

В широко известном на форуме проекте часов подобное реализовано.
Контактная информация:
Вымогатель припоя
Аватара пользователя
Сообщения: 601
Зарегистрирован: Пт фев 13, 2009 20:58:13
Откуда: Донецк

Сообщение DataLife »

Доброго времени суток, коты!
Не могу разобраться в, казалось бы, простых вещах.

МК: ATmega8

Суть: нужно сидеть в цикле while до тех пор, пока некая переменная не поменяет своё значение с 0 на 1.
Сама переменная изменяет своё значение в результате внешнего прерывания по INT1.

У меня же этот цикл пролетает, не дожидаясь изменения переменной, а далее, когда нужно зайти в цикл при условии "переменная == 1" он не заходит.

Может криво объяснил, но вот часть программы:
Спойлерunsigned char start = 0;


interrupt [EXT_INT1] void ext_int1_isr(void) // обработчик прерывания от кнопки СТАРТ
{
start++;
if (start == 2)
{start = 0;}
}

void main(void)
{

#asm("sei") // глобально разрешаем прерывания

GICR|=0x80; // разрешаем прерывание по INT1
MCUCR=0x08; // прерывание по спадающему фронту сигнала на INT1
GIFR=0x80;

while (start == 0) // пока не нажали кнопку пуска...
{
// делаем что-то, ПОКА переменная старт = 0
}

/*** ещё часть программы ***/


while (start == 1)

{
// делаем что-то, ПОКА переменная старт = 1
}
}
То есть цикл while (start == 0) у меня выполняется один раз, а в цикл while (start == 1) вообще не заходит...

Есть подозрения, что виной тому LCD 16x2, что подключён к порту D. Но нога с INT1 (PD3) как-раз не занята и её-то я и использую для прерываний...

Помогите, будьте добры...
Только те, кто предпринимают абсурдные попытки, смогут достичь невозможного.
Друг Кота
Аватара пользователя
Сообщения: 4905
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск

Сообщение WiseLord »

Для начала я бы сделал эту переменную volatile, коль скоро она в прерывании меняется.
Контактная информация:
Вымогатель припоя
Аватара пользователя
Сообщения: 601
Зарегистрирован: Пт фев 13, 2009 20:58:13
Откуда: Донецк

Сообщение DataLife »

Большое спасибо за подсказку, исправил :)
В принципе, проблему решил, всё работает. :beer:
Сделал подтяжку резистором на землю к ИНТ1, про неё я тоже забыл :)
Только те, кто предпринимают абсурдные попытки, смогут достичь невозможного.
Открыл глаза
Аватара пользователя
Сообщения: 63
Зарегистрирован: Сб мар 09, 2013 21:46:01
Откуда: Уфа

Сообщение alex-wolf »

Здравствуйте
кто сможет помочь
sba23-11xxx.c
(12.74 КБ) 293 скачивания
есть таблица для графо-генератора, и есть функция которая вызывается в момент запроса символа на индикатор
http://yandex.ru/clck/jsredir?from=yand ... 1926211216

есть немого лишнего, к каждому разряду -цвета нужно указывать таблицу, а это съедает память (еще нужно запихнуть для atmega8 еще и протокол mod_bus с фиксированным адресом , и читать указанные регистры, и исходя из значений выводить число, норма =зеленый, повышенный =оранжевый , критично = красный)

Изображение
Изображение

в конкретном примере значение числа производилось из чтение регистра секунд ds1307
Изображение
Изображение
Изображение


кусочек кода для оценки что получилось


pwm_=2;
//delay_ms(1000);
red_x10=red_x1='_'; green_x10='S';green_x1='T';green_x1='.';
delay_ms(1000);
pwm_=3;
BlkScrAll(); pwm_=1;
while (1) {
read_date_time(&sec,&minut,&hour,&day,&date,&month,&year);
ds1307_rddata=bcd2bin(ds1307_read(0x0));
//*
//используются для сравнения переменных, чисел (констант) и выражений.
//x < y // X меньше Y
//x > y // больше
//x <= y // меньше или равно
//x >= y // больше или равно
//x == y // равно
//x != y /* не равно
//| | // "ИЛИ" - только "ложь" и "ложь"
// дают "ложь"
//&& // "И" - только "истина" и "истина"
// дают "истина"
//! "НЕ" - логическое отрицание

//////////////////////////////////////////
// green_x1=((rc5_command));
// green_x10=((rc5_device));
//// green_x1=((rc5_command)10);
//// green_x10=((rc5_device)10);
////number_r(rc5_adr_out);
//green_x10_dp=(rc5_trg_out); red_x1_dp=(RC5_buffer [0]); green_x1_dp=(RC5_buffer [1]);
// BlkScrAll();

//

if((ds1307_rddata)<50) {
// green_x1=((ds1307_rddata)%10);
// green_x10=((ds1307_rddata)/10);
number_g(ds1307_rddata);
if ((ds1307_rddata) & (0x01) ) {green_x1_dp=(1);}
else {green_x1_dp=(0);};
}
else {
// red_x1=((ds1307_rddata)%10);
// red_x10=((ds1307_rddata)/10);
if ((ds1307_rddata) & (0x01) ) {green_x1_dp=(1);}
else {green_x1_dp=(0);};

number_r(ds1307_rddata);
}
if((ds1307_rddata)>44) {

// red_x1=((ds1307_rddata)%10);
// red_x10=((ds1307_rddata)/10);
// green_x1=((ds1307_rddata)%10);
// green_x10=((ds1307_rddata)/10);
number_y(ds1307_rddata);

if ((ds1307_rddata) & (0x01) ) {green_x1_dp=(1);}
else {green_x1_dp=(0);};

};

if((ds1307_rddata)>54) {

// BlkScrAll();
// red_x1=((ds1307_rddata)%10);
// red_x10=((ds1307_rddata)/10);
number_r(ds1307_rddata);
if ((ds1307_rddata) & (0x01) ) {green_x1_dp=(1);}
else {green_x1_dp=(0);}; };



if ((ds1307_rddata)==03 || PIND.2 == 0){;BlkScrAll();delay_ms(500);green_x10=(21);delay_ms(500);BlkScrAll();delay_ms(500);
green_x1=(((bcd2bin(ds1307_read(0x2))))%10);red_x1_dp=(1); green_x10=(((bcd2bin(ds1307_read(0x2))))/10);
delay_ms(1000);BlkScrAll();

BlkScrAll();delay_ms(500);number_g(bcd2bin(ds1307_read(0x1)));delay_ms(1000);BlkScrAll(); }

//// green_x1=red_x1=((bcd2bin(ds1307_read(0x0)))%10);
//red_x10=green_x10=((bcd2bin(ds1307_read(0x0)))/10);


delay_ms(1);

};

};
Контактная информация:
Вымогатель припоя
Аватара пользователя
Сообщения: 601
Зарегистрирован: Пт фев 13, 2009 20:58:13
Откуда: Донецк

Сообщение DataLife »

Товарищи, выручайте!

Не могу корректно выполнить поставленную задачу.
Делаю некое зарядное с мозгами на мега8.

Нужно мне увеличивать ШИМ, если напряжение на шунте (ток) ниже заданного.

Делал так:

while (1) {

while (ADC_shunt() <= ("условие"))
{
OCR2=OCR2+0x01;
if (OCR2==0xFF) break;
}

/** вывод разного на экран ***/
}

Дальше идёт вывод всего на дисплей, то не важно.
Казалось бы всё просто и верно: пока условие "напряжение меньше чем должно быть" - увеличиваем OCR2. Соответственно вырос реальный ток - выросло напряжение на шунте и тд. Если OCR2 достигло своего максимального значения, а условие не выполнено - выходим из цикла. Ну проще некуда!

Но!

Имитирую шунт подстроечником. Выставляю значения АЦП ниже заданного. Условие цикла "верно". ШИМ растёт, вижу (светодиод подцепил). Как только достигло максимального значения таки выходит из цикла и дальше выводит всё на экран. Но вот потом... Потом МК снова заходит в цикл, сбрасывает OCR2 :evil: в ноль и набирает снова до максимума и выходит из цикла.
Собственно вопрос:
1. Почему OCR2 сбрасывается?
2. Как это исправить?
Только те, кто предпринимают абсурдные попытки, смогут достичь невозможного.
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18675
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

DataLife писал(а):1. Почему OCR2 сбрасывается?
ну так вы закончили цикл в момент, когда OCR2==0xFF, а потом входите в цикл снова и увеличиваете OCR2 на 1. что будет если к байту 0xFF прибавить 1? байт станет равным 0.
DataLife писал(а):2. Как это исправить?
элементарно:

Код: Выделить всё

while (ADC_shunt() <= ("условие"))
{
if (OCR2==0xFF) break;
OCR2=OCR2+0x01;
}
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
Вымогатель припоя
Аватара пользователя
Сообщения: 601
Зарегистрирован: Пт фев 13, 2009 20:58:13
Откуда: Донецк

Сообщение DataLife »

ARV, ну просто от души спасибо! Пол дня решаю эту "загадку"!
Я-то думал, что если максимальное значение 256 есть, то добавив 1 мы его и не увеличим и не сбросим. А тут во как...
Ещё раз спасибо!
Только те, кто предпринимают абсурдные попытки, смогут достичь невозможного.
Друг Кота
Аватара пользователя
Сообщения: 4905
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск

Сообщение WiseLord »

Максимальное значение восьмибитного (unsigned) числа не 256, а 255. Если добавить 1, будет 256, а это единица (она "выпадает" из восьми бит) и 8 нулей, что равносильно 0.
Контактная информация:
Ответить

Вернуться в «AVR»