3х канальній измеритель напряжения на АТмега8

Вопросы настройки, программирования, прошивки микроконтроллеров и микросхем программируемой логики
Закрыто
Это не хвост, это антенна
Аватара пользователя
Сообщения: 1306
Зарегистрирован: Вс янв 18, 2009 20:51:02

Сообщение ooogo »

ARV у меня тоже возник вопросик, как распознать нажатие на две кнопки? Ведь одна кнопка нажмется раньше другой, а потом дребезг душить, не могу сообразить.
Реклама
Это не хвост, это антенна
Аватара пользователя
Сообщения: 1306
Зарегистрирован: Вс янв 18, 2009 20:51:02

Сообщение ooogo »

RaDevan зачем Вы инвертируете PIND, сразу наложите маску, а потом анализируйте состояние, например оператором switch, или после глушения дребезга возвращайте переменную темп, а в проге делайте анализ.
Реклама
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18785
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

ooogo писал(а):ARV у меня тоже возник вопросик, как распознать нажатие на две кнопки? Ведь одна кнопка нажмется раньше другой, а потом дребезг душить, не могу сообразить.
элементарно, Ватсон! нажалась одна кнопка, мы подождали 15 мс, снова смотрим - опа! там уже две кнопки. ну, раз прошлое и текущее состояние не одинаковы - мы вернем 0. а вот в следующий раз зайдем в эту функцию - а тут уже обе кнопки нажаты и никакого дребезга. и тогда вернется сразу двойной код. :)))
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18785
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

RaDevan писал(а):так мысль немного не уловил, это необходимо записать таким образом :
...
temp = ~PIND & ((1<<ch_plus) |(2<<ch_plus)|(3<<ch_plus)|(4<<ch_plus) |....);
...
на щет отступов учту на будущее
нет :) вот так:

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

#define ch_plus (1<<4)
#define ch_minus (1<<5)
ну и далее откорректировать все
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
Реклама
Эиком - электронные компоненты и радиодетали
Первый раз сказал Мяу!
Сообщения: 22
Зарегистрирован: Пн май 17, 2010 09:59:59
Откуда: Kiev

Сообщение RaDevan »

Вот так вот поднавоял, правильно ли мое суждение относительно переделки в функции кнопок и функции АЦП
unsigned char get_key(void)
{
unsigned char temp;
temp = ~PIND & ((1<<4) | (1<<5));
delay_ms(15);
if(temp != (~PIND & ((1<<4) | (1<<5))))
return 0;
else
return temp;
}
unsigned char get_adc(unsigned char chenal)
{
unsigned int result = 0;

ADMUX = chenal | (ADC_VREF_TYPE & 0xff);
ADCSR |= 1<<ADSC;

while(ADCSR & (1<<ADSC));

result = ADCW*5-ADCW/10;

return result;
}
Реклама
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18785
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

RaDevan писал(а):Вот так вот поднавоял, правильно ли мое суждение относительно переделки в функции кнопок и функции АЦП
unsigned char get_key(void)
{
unsigned char temp;
temp = ~PIND & ((1<<4) | (1<<5)); // ну где же константы, определенные при помощи define &!
delay_ms(15);
if(temp != (~PIND & ((1<<4) | (1<<5)))) // ну и здесь тоже - где?!
return 0;
else
return temp;
}
unsigned char get_adc(unsigned char chenal)
{
unsigned int result = 0;

ADMUX = chenal | (ADC_VREF_TYPE & 0xff); // & 0xFF - это лишнее, не имеющее никакого смысла действо
ADCSR |= 1<<ADSC;

while(ADCSR & (1<<ADSC));

result = ADCW*5-ADCW/10; // вы уверены, что тут не будет переполнения?

return result; // тип результата функции МЕНЬШЕ, чем возвращаемое число!!!
}
код оформляйте при помощи кнопки Code, а не Quote :)
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
Реклама
Это не хвост, это антенна
Аватара пользователя
Сообщения: 1306
Зарегистрирован: Вс янв 18, 2009 20:51:02

Сообщение ooogo »

ARV писал(а):элементарно, Ватсон! нажалась одна кнопка, мы подождали 15 мс, снова смотрим - опа! там уже две кнопки. ну, раз прошлое и текущее состояние не одинаковы - мы вернем 0. а вот в следующий раз зайдем в эту функцию - а тут уже обе кнопки нажаты и никакого дребезга. и тогда вернется сразу двойной код. :)))
ага, но если нажали на кнопку с разницей более 15 мс, то произойдет срабатывание сначала одной кнопки потом двух.
еще вопросик возник, пользователь нажал на кнопку и держит функция ведь постоянно будет возвращать код нажатия этой кнопки, дополнительно делать проверку в программе?
Первый раз сказал Мяу!
Сообщения: 22
Зарегистрирован: Пн май 17, 2010 09:59:59
Откуда: Kiev

Сообщение RaDevan »

Вот в итоге что получилось, но все равно не могу как то уяснить почему не переключаются каналы АЦП, буду очень благодарен за коменты по поводу моих ошибок :beer:

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

#include <mega8.h>
#include <stdio.h>
#include <delay.h>
#asm
   .equ __lcd_port=0x18 ;PORTB
#endasm
#include <lcd.h>
char lcd_buffer[31];
#define ch_plus  (1<<4)
#define ch_minus (1<<5) 
#define ADC_VREF_TYPE 0x00
unsigned int MAX_CHANEL=3;
unsigned int result;
unsigned int adc;
unsigned char get_key(void)
{ 
   unsigned char temp;
   
   temp = ~PIND & (ch_plus | ch_minus);
   
   delay_ms(15); 
   
   if(temp != (~PIND & (ch_plus | ch_minus)))
      return 0;
   else
      return temp;
}
unsigned char get_adc(unsigned char chenal)
{
   unsigned int result = 0;
   
           ADMUX = chenal | (ADC_VREF_TYPE & 0xff);
         
           delay_us(10);
         
           ADCSRA|=0x40;
         	
    while ((ADCSRA & 0x10)==0);
     
    result = (ADCW*5)-(ADCW/10);
       
    return ADCW; 
 } 
unsigned char lcd_output(unsigned char chanel, unsigned int result)
         {
         
         sprintf(lcd_buffer,"I=%4umA",result);
         
         lcd_clear();
         
         lcd_puts(lcd_buffer);
         
         delay_ms(25);
         }
void main(void)
{ 
  char chanel = 0;
  
  PORTD=0xFF;
  
  DDRD=0x00;
  
  ADMUX=ADC_VREF_TYPE & 0xff;
  
  ADCSRA=0x83;
  
  lcd_init(16);
  
while (1)
      { 
        char key = get_key();
        switch(key)
        {
             case ch_plus: 
              if(++chanel == MAX_CHANEL) chanel = 0;
         break;
             case ch_minus:
              if(!chanel) 
              chanel--;
         else
            chanel = MAX_CHANEL-1;
         break;
         } 
         adc = get_adc(chanel);
         lcd_output(chanel, adc);
         
          }
}

Это не хвост, это антенна
Аватара пользователя
Сообщения: 1306
Зарегистрирован: Вс янв 18, 2009 20:51:02

Сообщение ooogo »

unsigned char get_adc(unsigned char chenal) в этой строчке вы объявили локальную переменную.
глобальную переменную назовите, например chenal1, и объявите ее в начале программы, или же вообще не объяыляйте локальную переменную, а объявите только глобальную.
В момент у держания кнопки у вас постоянно вызывается процедура обработки нажатия, т.е. допустим нажатие примерно 500 мс, за это время много раз вызовится функция get_key() которая возвращает одно и тоже значение.
Первый раз сказал Мяу!
Сообщения: 22
Зарегистрирован: Пн май 17, 2010 09:59:59
Откуда: Kiev

Сообщение RaDevan »

уже это зделал, но итог особо не изменился, контроллер не переключает каналы при нажати на кнопки, выводится только 0й канал, интуитивно понимаю что баг гдето в описании функции кнопок, но немогу понять какой именно :?
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18785
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

ooogo писал(а):ага, но если нажали на кнопку с разницей более 15 мс, то произойдет срабатывание сначала одной кнопки потом двух.
еще вопросик возник, пользователь нажал на кнопку и держит функция ведь постоянно будет возвращать код нажатия этой кнопки, дополнительно делать проверку в программе?
естественно, если между нажатиями кнопок есть слишком большой промежуток времени - выдаст сначала одну кнопку, а потом обе. это абсолютно нормально - как иначе?!
что касается удержания, то решать эту проблему можно разными способами: можно в основном цикле проверять, когда надо, отпустил пользователь кнопку или нет (если требуются только одиночные нажатия), можно внутри get_key() организовать автоповтор, когда при нажатии выдается код, а при удержании начинается через определенные интервалы выдавать тот же код снова. есть и другие варианты - на любителя :)
я для своих программок сделал модуль buttons.h, в котором есть универсальная функция опроса кнопок с автоповтором, и пользуюсь этим всегда практически без изменений. исходник этого модуля можно выкопать из исходников термостатов и таймеров, которые я выкладываю на своем сайте.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18785
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

RaDevan, ответтьте на вопросы по вашему коду, пожалуйста.
1. #define ADC_VREF_TYPE 0x00 - вы уверены, то именно это значение задает правильный источник опорного напряжения АЦП? (я на память не помню, извините)
2. unsigned int MAX_CHANEL=3; - почему это у вас переменная? разве где-то по ходу программы это значение меняется? как правило, всеми заглавными буквами пишутся макросы, описанные при помощи define. Не лучше ли так #define MAX_CHANEL 3 ?
3. unsigned int result; это лишняя переменная - понимаете почему?
4. ADC_VREF_TYPE & 0xff - объясните, что это означает? какую задачу вы решаете этим действием?
5. функция get_adc() определена, как unsigned char, но возвращать пытается unsigned int - почему? это правильно? компилятор вам warning выдает? я вам на это указывал ранее, но вы проигнорировали.
6. для чего при выводе на дисплей сделана задержка в 25 миллисекунд?
7. ADMUX=ADC_VREF_TYPE & 0xff; - чему будет равен ADMUX в результате этих манипуляций? (вопрос перекликается с вопросом 4)
8. ADCSRA=0x83; - вы уверены, что это число как раз то, что вам надо?

после ответов обратите внимание на дискуссию вокруг постоянного возвращения кода нажатой кнопки - как вы обходите эту проблему? самый простой, но не самый лучший вариант - после обновления дисплея вставить ожидание отпускания кнопки: while(get_key()); прошу вас объяснить (для тренировки), почему этот способ далеко не самый лучший?

т.к. я считаю, что вы должны понимать, что вы делаете, поэтому считаю, что вы должны обязательно ответить на все поставленные перед вами вопросы. без этого я самоустранюсь от помощи вам.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
Первый раз сказал Мяу!
Сообщения: 22
Зарегистрирован: Пн май 17, 2010 09:59:59
Откуда: Kiev

Сообщение RaDevan »

Постараюсь ответить на большенство поставленых вопросов: (надеюсь некоторые ответы помогут мне вновь понять сам процесс :) )
1. #define ADC_VREF_TYPE 0x00 - вы уверены, то именно это значение задает правильный источник опорного напряжения АЦП

1.1. Это значение генерит непосредственно CodeVision, когда я выбираю тип опорного напряжения при создании проэкта с помощью CodeWizard (ADC -> Volt.Ref -> AREF pin), потому думаю что уверен в правильности.

2. unsigned int MAX_CHANEL=3; - почему это у вас переменная? разве где-то по ходу программы это значение меняется? как правило, всеми заглавными буквами пишутся макросы, описанные при помощи define. Не лучше ли так #define MAX_CHANEL 3 ?

1.2. Это наше значение максимального количества опрашиваемых каналов АЦП и оно равно 3, по идеи при компилировании название MAX_CHANEL должно заменятся на 3, но этого не происходит и выдается ошибка. Потому я прописал его unsigned int MAX_CHANEL=3; и ошибки пропали.

3. unsigned int result; это лишняя переменная - понимаете почему?

1.3. Да понял так как result; уже определен как локальная переменная в unsigned char get_adc() как unsigned char result = 0; и более нигде не применяется, тем более получается не совмещение локальной и глобальной переменной, спасибо разобрался.

4. ADC_VREF_TYPE & 0xff - объясните, что это означает? какую задачу вы решаете этим действием?

1.4. Непосредственно выбор опорного напряжения и определение его значения, это как я понял из книжек по коде вижену, но в итоге я его убрал, в программе более не использую.

5. функция get_adc() определена, как unsigned char, но возвращать пытается unsigned int - почему? это правильно? компилятор вам warning выдает? я вам на это указывал ранее, но вы проигнорировали.

1.5. Это не правильно, компилятор выдает Варнинг, поменял возвращаемый результат на unsigned char варнинг отвалился , СПАСИБО - дельная подсказка.

6. для чего при выводе на дисплей сделана задержка в 25 миллисекунд?

1.6. Небольшая задержка перед выводом вновь считаного результата, это я так понял .

7. ADMUX=ADC_VREF_TYPE & 0xff; - чему будет равен ADMUX в результате этих манипуляций? (вопрос перекликается с вопросом 4)

1.7. ADMUX=0х00 & 0xff; как итог адмукс не может определится так как заданы два ранопротивоположных результата и выводит наверняка первый 0х00;

8. ADCSRA=0x83; - вы уверены, что это число как раз то, что вам надо?

1.8 Это число тоже генерится коде визардом не разобрался толком но думаю это функция котороя задает коефициент деления тактовой частоты АЦП
Это не хвост, это антенна
Аватара пользователя
Сообщения: 1306
Зарегистрирован: Вс янв 18, 2009 20:51:02

Сообщение ooogo »

ARV писал(а):я для своих программок сделал модуль buttons.h, в котором есть универсальная функция опроса кнопок с автоповтором, и пользуюсь этим всегда практически без изменений. исходник этого модуля можно выкопать из исходников термостатов и таймеров, которые я выкладываю на своем сайте.
понял, спасибо посмотрю как время будет.
по поводу кнопок, в данном случае наверное так будет лучше?

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

unsigned char temp1;

unsigned char get_key(void)
{ 
   unsigned char temp;
   
   temp = ~PIND & (ch_plus | ch_minus);
   
   delay_ms(15); 
   
   if(temp != (~PIND & (ch_plus | ch_minus)))
        {        
         temp1=0;
         return 0;
         }
   else
        {
         if(temp==temp1) return 0xFF;
         else
              {
                temp1=temp;
                return temp;               
               }
         }
}
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18785
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

позволю себе прокомментировать ваш ответ прямо по тексту (синим).
RaDevan писал(а):Постараюсь ответить на большенство поставленых вопросов: (надеюсь некоторые ответы помогут мне вновь понять сам процесс :) )
1. #define ADC_VREF_TYPE 0x00 - вы уверены, то именно это значение задает правильный источник опорного напряжения АЦП

1.1. Это значение генерит непосредственно CodeVision, когда я выбираю тип опорного напряжения при создании проэкта с помощью CodeWizard (ADC -> Volt.Ref -> AREF pin), потому думаю что уверен в правильности.

2. unsigned int MAX_CHANEL=3; - почему это у вас переменная? разве где-то по ходу программы это значение меняется? как правило, всеми заглавными буквами пишутся макросы, описанные при помощи define. Не лучше ли так #define MAX_CHANEL 3 ?

1.2. Это наше значение максимального количества опрашиваемых каналов АЦП и оно равно 3, по идеи при компилировании название MAX_CHANEL должно заменятся на 3, но этого не происходит и выдается ошибка. Потому я прописал его unsigned int MAX_CHANEL=3; и ошибки пропали.
совершенно не правильный подход - сделать непонятно что и радоваться, что ошибки пропали. надо всегда разбираться, в чем было дело, ибо определение константы через дефайн - наиболее правильный подход, который просто обязан работать.

3. unsigned int result; это лишняя переменная - понимаете почему?

1.3. Да понял так как result; уже определен как локальная переменная в unsigned char get_adc() как unsigned char result = 0; и более нигде не применяется, тем более получается не совмещение локальной и глобальной переменной, спасибо разобрался.

4. ADC_VREF_TYPE & 0xff - объясните, что это означает? какую задачу вы решаете этим действием?

1.4. Непосредственно выбор опорного напряжения и определение его значения, это как я понял из книжек по коде вижену, но в итоге я его убрал, в программе более не использую.
я имел ввиду непонятное побитовое И с числом 0xFF. в результате этой операции ВСЕГДА будет то же самое число, т.е. ADC_REF_TYPE. следовательно, без всяких операций можно просто использовать ADC_REF_TYPE в чистом виде, так сказать.

5. функция get_adc() определена, как unsigned char, но возвращать пытается unsigned int - почему? это правильно? компилятор вам warning выдает? я вам на это указывал ранее, но вы проигнорировали.

1.5. Это не правильно, компилятор выдает Варнинг, поменял возвращаемый результат на unsigned char варнинг отвалился , СПАСИБО - дельная подсказка.
само собой, подсказка дельная :))) только вы ей воспользовались неправильно. внутри функции вы используете значение АЦП, которое максимум может быть равным 1023. это число в unsigned char никак не влезет, поэтому вы обрекаете себя на удивительные открытия, когда ток ваш рос-рос, а потом обнулился и стал расти снова... подумайте еще раз, как надо изменить тип результата, чтобы избежать проблем

6. для чего при выводе на дисплей сделана задержка в 25 миллисекунд?

1.6. Небольшая задержка перед выводом вновь считаного результата, это я так понял .
хорошим тоном считается использование внутри функции только тех действий, которые эта функция обязана делать для самой себя, поэтому задержка перед следующим измерением ну никак не должна находиться внутри функции индикации. ее место в основном цикле.

7. ADMUX=ADC_VREF_TYPE & 0xff; - чему будет равен ADMUX в результате этих манипуляций? (вопрос перекликается с вопросом 4)

1.7. ADMUX=0х00 & 0xff; как итог адмукс не может определится так как заданы два ранопротивоположных результата и выводит наверняка первый 0х00;
не наверняка, а однозначно! см. выше. уберите вы своё & 0xFF наконец - уже котороый пост я вам на это намекаю!

8. ADCSRA=0x83; - вы уверены, что это число как раз то, что вам надо?

1.8 Это число тоже генерится коде визардом не разобрался толком но думаю это функция котороя задает коефициент деления тактовой частоты АЦП
см. самый первый пост - надо разобраться, что там ваш визард генерирует! я потому и не люблю эти визарды, что они делают сами, а потом гадай, что именно они делают. возможно, все правильно, а возможно и нет...
и вы забыли еще вопросик в конце моего предыдущего поста :)
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
Первый раз сказал Мяу!
Сообщения: 22
Зарегистрирован: Пн май 17, 2010 09:59:59
Откуда: Kiev

Сообщение RaDevan »

Честно говоря не могу толком ответить на вопросик, так как еще нету столь большего опыта работы над программированием МК, буду рад если Вы напрвите меня на путь истинный
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18785
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

ладно, будем надеяться, что впоследствии вы поймете, в чем там фишка :) а пока - просто сделайте ожидание отпускания клавиши, как я советовал, и у вас должно все заработать более-менее нормально.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
elf
Открыл глаза
Сообщения: 60
Зарегистрирован: Чт окт 29, 2009 23:22:03

Сообщение elf »

Доброго времени суток!!!
Народ нужна помощь- собрал вольтметр на атмеге8 все работает, но показания скачут как бешаные (фильтр на вод ацп поставил ) думаю надо усреднить показания АЦП
Но как?

пробую вот так:
#include <mega8.h>
#include <delay.h>
#include <stdio.h>

#asm
.equ __lcd_port=0x18 ;PORTB
#endasm
#include <lcd.h>
char lcd_buffer[31];
unsigned int result;
unsigned int c;
unsigned int i;
unsigned int r2 ;
unsigned int result2 [64];


void main(void)
{

PORTC=0x00;
MCUCR = 0x0A;
GICR = 0xC0;
lcd_init(16);


while(1){

for(i=0; i<64;i++)
{ result= 0;
ADMUX=0;
ADCSRA=0b11011111; //включаем ацп
result2 = (ADCW*5-ADCW/10); //пишем в масив значение ацп
result= ( result+result2) /i ; //усредняем
}
lcd_gotoxy(0,0);
sprintf(lcd_buffer,"ADC=% umV" ,result );//
lcd_puts(lcd_buffer);
}

}


- ни хрена не выходит
Где тут грабли???
Помогите замучился уже :(
Последний раз редактировалось elf Пн май 24, 2010 22:01:35, всего редактировалось 1 раз.
Первый раз сказал Мяу!
Сообщения: 22
Зарегистрирован: Пн май 17, 2010 09:59:59
Откуда: Kiev

Сообщение RaDevan »

а что у вас служит опорным напряжением ???
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18785
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

elf писал(а):- ни хрена не выходит
Где тут грабли???
Помогите замучился уже :(
а вы прочтите десяток предыдущих постов - там все есть: от советов оформлять код как положено до работы с АЦП. учитесь на том, что уже сказано, а не вопите - по 100 раз повторять одно и то же нет никакого желания.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
Закрыто

Вернуться в «Микроконтроллеры и ПЛИС»