Уважаемые инженеры, поздравляю Всех с наступившим Новым Годом и с наступающем Рождеством!!!
Предлагаю приколоться над работой AVR Studio и AVR-gcc. Как только программа проводит 15 измерений, проходит все проверки, посылает управляющий импульс и доходит до конца функции ISR(TIMER1_COMPA_vect), она «уходит в себя» на неопределенное время, и не останавливается нигде. Только если нажать «паузу» почему-то останавливается на sei() ; хотя если там же поставить BreakPoint сама там не останавливается. Глюки? Или специфика работы AVR-Studio. Программа написана для atMega644.
| Код | //05 января 2009 #include <avr\io.h> #include <avr\signal.h> #include <avr\interrupt.h> //#include <avr\delay.h>
#define INERTZONE 3 // Зона нечувствительности. #define LIGHTIME 40 // Задержка включения светодиода после поворота ручки (умножить на время срабатывания таймера = сек). #define IZMNUM 15 // Проводим такое кол-во измерений перед тем как начать вращение #define COEFF 0.0732422
volatile unsigned int iDelay, iADCResult, iADCResultOld, iADCResultMin, iADCResultMax, i, iLightDelay ; //время задержки моргания светодиода. volatile unsigned char cIzmCount ; //исчетчик количества измерений перед тем как начать вращение unsigned int iADCResultArray[IZMNUM] ; //Массив в котором будут хранится измерения. double fCoeff ; unsigned char cGoodToRottate ; //Устраивает ли нас точность измерений и будем ли вращать машинку. unsigned char cRottating ; //Если 0xFF идет вращение, если 0x00 вращение не идет. unsigned int iADCResultLoc ; unsigned char cADCReg ;
int main(void) { cRottating = 0x00 ; fCoeff = 0.0732422 ;
//---------Настройка Таймера 0------- // TCCR0A = 0x00; // TCCR0B = 0x00; //стоп
// TCNT0 = 0x00; // OCR0A = 0x4F;
// TIMSK0 = 0x02; //прерывание по совпадению с OCR0A // TCCR0B = 0x04; //старт с делителем //---------------------------------
//---------Настройка Таймера 1------- // TCCR1A = 0x00; TCCR1B = 0x00; //стоп
TCNT1 = 0x00; // OCR1AH = 0x04; // OCR1AL = 0x00; // OCR1A = 976 ; //1 сек с делителем на 1024 // OCR1A = 48 ; //0.05 сек с делителем на 1024 OCR1A = 20 ; //0.02 сек с делителем на 1024
TIMSK1 = 0x02; //прерывание по совпадению с OCR0A TCCR1B = 0x05; //старт с делителем на 1024 //---------------------------------
//----------Настройка АЦП---------- DDRD = 0x0 ; PORTD = 0x0 ; DIDR0=0x01 ; // Использовать для АЦП будем PA0 //ADMUX = 0b11100000 ; //Внутреннее опорное напряжение 2.56В и результат со сдвигом влево. ADMUX = 0b11000000 ; //Внутреннее опорное напряжение 2.56В и результат со сдвигом вправо. ADCSRA = 0b10000000 ; //Включение АЦП без прерывания. ADCSRA |= 0x40 ; //Запускаем преобразование. //----------------------------------
DDRB = 0x05 ; PORTB = 0x01 ; //Выключаем с.д. iLightDelay = 0 ; //Эта переменная считает длительность горения с.д. cIzmCount = 0 ; //Считает количество проведенных измерений.
sei() ; while(1) { } }
unsigned int Izmerenie(void) //Функция измерения АЦП {
TCNT1 = 0x00; //reload counter value
//Запускаем АЦП ADCSRA|=0x40; // как только измерение закончится //этот бит пропадет, зато установится // бит ADIF. //Ждем завершения преобразования cADCReg = 0b01010000 & ADCSRA ;
while (cADCReg != 0b00010000) { cADCReg = 0b01010000 & ADCSRA ; //Делаем поразрядное "и" //что бы оставить только //нужные нам биты ADSC и ADIF. }
//Считываем данные ADC iADCResultLoc = ADC ;
return (iADCResultLoc) ; }
ISR(TIMER1_COMPA_vect) { cGoodToRottate = 0x00 ; // if (cRottating == 0x00) //Если еще идет предыдущее вращение, не делаем ничего. { if (cIzmCount<IZMNUM) //Проводим несколько измерений (IZMNUM) и смотрим устраивает ли нас точность. { iADCResultArray[cIzmCount] = Izmerenie() ; cIzmCount ++ ; } else { //Если измерения выполнены смотрим устраивает ли нас точность измерений. iADCResultMax = 0 ; iADCResultMin = 0xFFFF ;
for (cIzmCount=0; cIzmCount<IZMNUM; cIzmCount++) { //все результаты не должны сильно отличатся друг от друга //Ищем максимум и минимум if (iADCResultMax < iADCResultArray[cIzmCount] ) iADCResultMax = iADCResultArray[cIzmCount] ; if (iADCResultMin > iADCResultArray[cIzmCount] ) iADCResultMin = iADCResultArray[cIzmCount] ; } //Пусть измерения укладываются в 15 ; if (iADCResultMax-iADCResultMin<15) { // Если точность устраивает, расчитываем среднеарифметическое //и сравниваем со старым значением iADCResult=0 ; for (cIzmCount=0; cIzmCount<IZMNUM; cIzmCount++) { iADCResult = iADCResult + iADCResultArray[cIzmCount] ; } iADCResult = iADCResult/IZMNUM ; cIzmCount = 0 ; //Проверяем на сколько полученое значение отличается от пошлого. //Если превышает зону не чувствительности (INERTZONE) запускаем вращение машинки if (iADCResult > iADCResultOld+INERTZONE || iADCResult < iADCResultOld-INERTZONE) //Зона не чувствительности. { cGoodToRottate = 0xFF ; //Если все ОК запускаем вращение сервы. iADCResultOld = iADCResult ; } } } }
if (cGoodToRottate==0xFF) { //Расчиттываем задержку моргания светодиода iDelay = (iADCResult+1)*COEFF+37 ; //это будет время задержки моргания светодиода
cRottating = 0xFF ; //Устанавливаем переменную в режим вращения ; PORTB=PORTB & 0x04 ; //включаем светодиод (лог 0 на 1ую ножку). }
if ( cRottating == 0xFF && iLightDelay<LIGHTIME) //Если идет вращение { i=0; PORTB=PORTB | 0x04 ; //Запускаем управляющий импульс (лог 1 на 3ю ножку) while(i<iDelay) { i++ ; } PORTB=PORTB & 0x01 ; //Останавливаем управляющий импульс (лог 1 на 3ю ножку, значение ножки 1 (с.д. не меняется)) iLightDelay ++ ; } else { cRottating = 0x00 ; //Выключаем вращение PORTB=PORTB | 0x01 ; //выключаем с.д. (лог 1 на 1ую ножку) если время его горения вышло (значение бита управления сервой останется неизменным) iLightDelay = 0 ; }
}
|
|