реклама на сайте
подробности

 
 
 
Reply to this topicStart new topic
> Проблемы с АЦП ATmega48, код на Си
sergeus
сообщение May 24 2010, 17:15
Сообщение #1


Частый гость
**

Группа: Участник
Сообщений: 157
Регистрация: 11-12-07
Из: Москва
Пользователь №: 33 174



Программа должна оцифровывать сигнал на входе и в зависимости от уровня управляет ШИМ на выходе.

Непонятки с АЦП, оно работает только один раз, а должно работать при каждом вызове подпрограммы оцифровки.

Помогите, пожалуйста. Бьюсь уже несколько часов. Код на WinAVR:

Код
/*    ATmega48, тактирование внутреннее 8 MHz*/

//#define F_CPU 8000000

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

void set_pwm(unsigned char, unsigned char, unsigned char);
int adc_convert(unsigned char);

unsigned int max=1, min=1, average=0;
double factor=0;
unsigned char abc = 0;

ISR(TIMER1_OVF_vect){
  unsigned int input;
  
  input = adc_convert(0);
  if (input > max) max = input;
  
  factor = (double)input/(double)max
  
  OCR0A =  (unsigned char)(0xFF * factor);

  TCNT1 = 65503;                                    // 4mS
}

// ********************  ADC   *****************************

void adc_init(void){
  ADMUX = (0<<REFS1)|(1<<REFS0);                                        // AVCC - 5v
  ADCSRA = (1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);                // CK/128
  //ADCSRB = (1<<ADTS2)|(1<<ADTS1)|(0<<ADTS0);                          // timer1 overflow
}

int adc_convert(unsigned char channel){
  unsigned int result;
  
  ADMUX = (ADMUX & 0xF0)|channel;
  ADCSRA |= (1<<ADSC);

  while (!(ADCSRA & (1<<ADSC)));
  
  
  result = ( ((int)ADCH << 8) | (int)ADCL);
  return result;
}



// ********************  PWM   *****************************

void pwm_init(void){
  // Timer0 init
  DDRD |= (1<<PD5)|(1<<PD6);
  TCCR0A |= (1<<COM0A1)|(1<<COM0B1)|(1<<WGM01)|(1<<WGM00);        // Fast PWM
  TCCR0B |= (1<<CS00);                                                // CK/1, F pwm =
  
  // Timer2 init
  DDRB |= (1<<PB3);
  TCCR2A |= (1<<COM2A1)|(1<<WGM21)|(1<<WGM20);                    // Fast PWM
  TCCR2B |= (1<<CS20);                                                // CK/1, F pwm =
}

void set_pwm(unsigned char r, unsigned char g, unsigned char b){
  OCR0A = r;
  OCR0B = g;
  OCR2A = b;
}

void timer1_init(void){
  TCCR1B |= (1<<CS12)|(0<<CS11)|(1<CS10);            // step = 1/8mS
  TIMSK1 |= (1<<TOIE1);                            // int. ovf. enable
  TCNT1 = 65505;                                    // 1000mS
}


int main (void) {
  adc_init();
  pwm_init();                                        // timers 0 & 2 init
  timer1_init();
  
  sei();
  while(1);
}
Go to the top of the page
 
+Quote Post
SasaVitebsk
сообщение May 24 2010, 20:31
Сообщение #2


Гуру
******

Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521



Вот пишут-пишут разные люди и в разных темах. Всё равно что об стенку горох! Хоть ты где-нибудь на центральной вкладке размести!

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

Не ужели нет фантазии как это можно реализовать по-другому?

1 вариант) Есть у вас прерывание TIMER1_OVF. В начале прерывания читаете АЦП и перестартовываете его. Само прерывание должно приходить гарантировано реже чем время измерения по АЦП. Соответственно ждать ничего не надо.

2 вариант) Проверяете завершено ли преобразование и результат размещаете в памяти. Данные берёте из памяти. (То есть развязываете факт измерения и факт принятия решения). В этом случае частота вызова TIMER1_OVF может быть любой.

Можно ещё 10 вариантов придумать.
Go to the top of the page
 
+Quote Post
sergeus
сообщение May 25 2010, 07:36
Сообщение #3


Частый гость
**

Группа: Участник
Сообщений: 157
Регистрация: 11-12-07
Из: Москва
Пользователь №: 33 174



Спасибо, SasaVitebsk!

Дельные советы, задумывался об этом, но не реализовал. Дело было в именах переменных и считывании их регистров АЦП. Сейчас все работает.

Сделаю прерывания, как мне посоветовали. Еще раз спасибо smile.gif
Go to the top of the page
 
+Quote Post
777777
сообщение May 29 2010, 17:53
Сообщение #4


Профессионал
*****

Группа: Участник
Сообщений: 1 091
Регистрация: 25-07-07
Из: Саратов
Пользователь №: 29 357



Цитата(sergeus @ May 24 2010, 21:15) *
Код
  result = ( ((int)ADCH << 8) | (int)ADCL);

Еще очень важен порядок чтения байт из регистров, об этом написано в даташите. Если лень читать, можно написать
Код
  result = ADC;

и компилятор сгенерирует правильную последовательность.
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 18th July 2025 - 12:31
Рейтинг@Mail.ru


Страница сгенерированна за 0.01355 секунд с 7
ELECTRONIX ©2004-2016