Atmega640 не генерирует сигнал

Обсуждаем контроллеры компании Atmel.
Ответить
Родился
Сообщения: 4
Зарегистрирован: Сб дек 14, 2019 02:48:10

Сообщение warfa »

Здравствуйте! Мне нужно разработать в Proteus генератор освещения на Atmega640. Также микроконтроллер должен генерировать сигнал. При изменении напряжения на потенциометре загорается определенное количество индикаторов. Но вот сигнал не генерируется. В коде есть несколько предупреждений, но не смотря на это регулятор работает. Как только убираю все ошибки, то вообще не работает. Подскажите, пожалуйста, что не так в схеме или коде из-за чего сигнал не генерируется? https://cloud.mail.ru/public/2VPz/4Vp5sJpWJ
P.S. файл proteus не прикреплялся, поэтому загрузил в облако и прикрепил ссылку.

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

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#define ADC_VREF_TYPE 0x40
unsigned int time = 0;
// Timer 0 output compare A interrupt service routin
ISR(TIMER0_CMP_vect)
{
 if(time <= 1152)
    time++;
 else
    time = 0;
    if(time >= 0 && time <= 63)
       {
        PORTC = 4*time;
       }
    else
       if(time > 63 && time <= 576)
          {
           PORTC =  255;
          }
       else
          if(time > 576 && time <= 832)
             {
              PORTC = -time + 832;
             } 
          else
             {
              PORTC = 0;
             } 
}
/// Read the AD conversion result
unsigned int read_adc(unsigned char adc_input)
{
ADMUX=(adc_input & 0x1f) | (ADC_VREF_TYPE & 0xff);
if (adc_input & 0x20) ADCSRB |= 0x08;
else ADCSRB &= 0xf7;
// Delay needed for the stabilization of the ADC input voltage
int i=0;
while(i<1000)
{i++;}
// Start the AD conversion
ADCSRA|=0x40;
// Wait for the AD conversion to complete
while ((ADCSRA & 0x10)==0);
ADCSRA|=0x10;
return ADCW;
}      
void main(void)
{
// Crystal Oscillator division factor: 1
#pragma optsize-
CLKPR=0x80;
CLKPR=0x00;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif
PORTB=0x00;
DDRB=0xFF;
PORTC=0x00;
DDRC=0xFF;
// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: 125,000 kHz
// Mode: CTC top=OCR0A
// OC0A output: Disconnected
// OC0B output: Disconnected
TCCR0A=0x02;
TCCR0B=0x03;
TCNT0=0x00;
OCR0A=0xC3;
OCR0B=0x00;
// Timer/Counter 0 Interrupt(s) initialization
TIMSK0=0x02;
// ADC initialization
// ADC Clock frequency: 125,000 kHz
// ADC Voltage Reference: AVCC pin
// ADC Auto Trigger Source: Free Running
ADMUX=ADC_VREF_TYPE & 0xff;
ADCSRA=0xA6;
ADCSRB&=0xF8;   
// Global enable interrupts
while (1)
      {
       if(read_adc(0) >=0 && read_adc(0) <= 205)
         PORTB = 0x1F;
       else
         if(read_adc(0) > 205 && read_adc(0) < 410)
           PORTB = 0x0F;
         else
           if(read_adc(0) >= 410 && read_adc(0) <= 615)
             PORTB = 0x07;   
           else 
             if(read_adc(0) > 615 && read_adc(0) < 820)
               PORTB = 0x03;
               else 
                 if(read_adc(0) >= 820 && read_adc(0) < 1023) 
                    PORTB = 0x01; 
                 else
                    PORTB = 0x00; 

      }
}
Реклама
Друг Кота
Аватара пользователя
Сообщения: 6322
Зарегистрирован: Вт апр 24, 2007 07:45:40
Откуда: Minsk

Сообщение Jack_A »

Я для АВР пишу на асме и глубоко в эту прогу не вникал, но вот что меня царапнуло.
(read_adc(0) - это функция чтения АЦП, и в ветвящихся if'ах она вызывается снова и снова ? Если умный компилятор не уберет эту дичь, то думаю, что нужно было бы так: один раз считать АЦП в переменную и уж затем это единственное считанное значение сравнивать с константами ветвления. Я так думаю.
Изображение
Реклама
Мудрый кот
Сообщения: 1849
Зарегистрирован: Вс дек 25, 2016 08:34:54

Сообщение Dimon456 »

Код скопипастил из cvavr.

Для начало стоило бы убрать "предупреждения".
Убрать из кода

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

#pragma optsize-
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif
Далее, по поводу

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

ISR(TIMER0_CMP_vect)
стоило бы заглянуть в файлик iomxx0_1.h.
Ну и раз прерывание используется то разрешить его

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

// Global enable interrupts
sei();
На будущее, здесь мало кто будет разбираться с

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

TCCR0A=0x02;
TCCR0B=0x03;
гораздо удобнее для восприятия писать так

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

TCCR0A=(0<<COM0A1) | (0<<COM0A0) | (0<<COM0B1) | (0<<COM0B0) | (1<<WGM01) | (0<<WGM00);
TCCR0B=(0<<WGM02) | (0<<CS02) | (1<<CS01) | (1<<CS00);
Какой сигнал на выходе хотите получить?
Друг Кота
Аватара пользователя
Сообщения: 6322
Зарегистрирован: Вт апр 24, 2007 07:45:40
Откуда: Minsk

Сообщение Jack_A »

[uquote="Dimon456",url="/forum/viewtopic.php?p=3756285#p3756285"]гораздо удобнее для восприятия писать так

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

TCCR0A=(0<<COM0A1) | (0<<COM0A0) | (0<<COM0B1) | (0<<COM0B0) | (1<<WGM01) | 0<<WGM00);
TCCR0B=(0<<WGM02) | (0<<CS02) | (1<<CS01) | (1<<CS00);
Какой сигнал на выходе хотите получить?[/uquote]
Если не загружать строку бессмысленными
TCCR0A=(0<<COM0A1) | (0<<COM0A0) | (0<<COM0B1) | (0<<COM0B0) или (0<<WGM02) | (0<<CS02)
то читать будет еще удобнее. 0 как ни двигай, он нулем и останется, так что выбросив эту хрень, получим нули по умолчанию во всех разрядах, кроме тех, что со "сдвинутыми" единичками.
Изображение
Реклама
Эиком - электронные компоненты и радиодетали
Ответить

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