AVR Раздел по микроконтроллерам компании Atmel - AVR / ATtiny / ATmega / ATMega128 / ATxmega, вопросы по программированию в AVR studio и все, относящееся к AVR... |
11.09.2016, 09:45
|
|
Временная регистрация
Регистрация: 05.10.2010
Сообщений: 68
Сказал спасибо: 12
Сказали Спасибо 8 раз(а) в 8 сообщении(ях)
|
Помогиге с кодом по датчику света - отключение, attiny13
Всем привет! Решил потихоньку освоить таймеры, отсчет времени на attiny13, начал с самого простого проекта датчика света, причем он нужен для видеонаблюдения, вкл/выкл прожектора на ик-светодиодах мощных.
Вроде рассчитал время правильно. Чип от внутреннего генератора 9,6MHz, предделитель 1/1. Настраивал счетчик лопатит на 37,500кГц, указываем значение регистра сравнения равное 0хFA равно 250, 18750/250=150 в секунду. Задаю в коде 30 секунд, потом включение... в протусе насчитает 20 сек с простым кодом для проверки правильности таймера.
Алгоритм следующий, если на улице стемнело, больше указного порога который мы записали в ЕППРОМ, ждем 20 сек, если все так же темно, но включаем прожектор. И наоборот если стало светло, то через 20 сек выключаем свет. Кнопкой на PORTB.0 мы программируем порог включения-отключения света простым нажатием. Светодиод на PORTB2 показывает что якобы записали.
Код:
|
#include ‹tiny13.h›
#include ‹delay.h›
unsigned int timer; // наша переменна
unsigned int s; // наша переменна для секунд
int s1=0; // наша переменная флага
eeprom int adc; //объявляем численную переменную, хранящийся в ЕППРОМ
// Timer 0 output compare A interrupt service routine
interrupt [TIM0_COMPA] void timer0_compa_isr(void)
{
timer++;
if(timer==150) {s++;timer=0;} // если равно 150, увеличиваем на секунду и сбрасываем
TCNT0=0x00;
}
#define ADC_VREF_TYPE 0x00
// Read the AD conversion result
unsigned int read_adc(unsigned char adc_input)
{
ADMUX=adc_input | (ADC_VREF_TYPE & 0xff);
// Delay needed for the stabilization of the ADC input voltage
delay_us(10);
// Start the AD conversion
ADCSRA|=0x40;
// Wait for the AD conversion to complete
while ((ADCSRA & 0x10)==0);
ADCSRA|=0x10;
return ADCW;
}
// Declare your global variables here
void main(void)
{
int i; // переменная хранящаяся в SRAM
int eeprom *adc; // указатель ЕЕПРОМ
// Crystal Oscillator division factor: 1
#pragma optsize-
CLKPR=0x80;
CLKPR=0x00;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif
// Input/Output Ports initialization
// Port B initialization
// Func5=In Func4=In Func3=In Func2=Out Func1=Out Func0=In
// State5=T State4=T State3=T State2=0 State1=0 State0=P
PORTB=0x01;
DDRB=0x06;
// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: 37,500 kHz
// Mode: Normal top=0xFF
// OC0A output: Disconnected
// OC0B output: Disconnected
TCCR0A=0x00;
TCCR0B=0x04;
TCNT0=0x00;
OCR0A=0xFA; //37500/250=150 за сеукнду
OCR0B=0x00;
// Timer/Counter 0 Interrupt(s) initialization
TIMSK0=0x04;
// ADC initialization
// ADC Clock frequency: 150,000 kHz
// ADC Bandgap Voltage Reference: Off
// ADC Auto Trigger Source: ADC Stopped
// Digital input buffers on ADC0: On, ADC1: On, ADC2: On, ADC3: On
DIDR0&=0x03;
DIDR0|=0x00;
ADMUX=ADC_VREF_TYPE & 0xff;
ADCSRA=0x86;
// Global enable interrupts
#asm("sei")
s1=0; //флаг сброшен
i=*adc; //считали значения из памяти по указателю
while(1){
//*************БЛОК ВКЛЮЧЕНИЯ ПРОЖЕКТОРА*************
if((read_adc(2) ‹ i) && (s1 == 0)){//если света меньше заданного порога и флаг сброшен
s1 = 1;//включаем флаг
s = 0;//секунды в ноль
}
if(s1 == 1){//если по прежнему сохраняется условие
if(s == 20){//насчитал больше 20 сек
PORTB.1 = 1;//вкл. прожектор
s1 = 0;}//сбросил флаг
}
//************************************************** ***
//************БЛОК ВЫКЛЮЧЕНИЯ ПРОЖЕКТОРА***************
if((read_adc(2) › i) && (s1 == 0)){//если света больше заданного порога
s1 = 2;//меняем флаг
s = 0;//секунды в ноль
}
if(s1 == 2){//условие сохраняется
if(s == 20){//отсчитали 20 сек
PORTB.1 = 0;//выкл. прожектор
s1 = 0;}//флаг сбросили
}
//************************************************** ****
//***********Запись в ЕЕПРОМ****************************
if (PINB.0==0){//нажали на кнопку
PORTB.2=1;
delay_ms(200);//светодиод моргнул
PORTB.2=0;
delay_ms(2000);//подождали 2 сек
i=read_adc(2);*adc=i;//переменная равна значению АЦП, записываем значение АЦП по указателю в ЕППРОМ
PORTB.2=1;
delay_ms(200);
PORTB.2=0;
delay_ms(500);
PORTB.2=1;
delay_ms(200);//три раза моргнули светодиодом, фигня полнейшая
PORTB.2=0;
delay_ms(500);
PORTB.2=1;
delay_ms(200);
PORTB.2=0;
}
}
} |
Вопрос стал в следующем, если значение ацп упало ниже порога, и продержалось там более 20 сек, то включаю свет. Но если значение ацп, стало выше порога + 20 сек, то выключить свет не могу. Было несколько вариантов, как это реализовать, но условие включения перекрывало выключение, мешались друг другу... приложил свои ошибки внизу....
Код:
|
//*************БЛОК ВКЛЮЧЕНИЯ ПРОЖЕКТОРА*************
if((read_adc(2) ‹ i) && (s1 == 0)){//если света меньше заданного порога и флаг сброшен
s1 = 1;//включаем флаг
s = 0;//секунды в ноль
}
if(s1 == 1){//если по прежнему сохраняется условие
if(s == 20){//насчитал больше 20 сек
PORTB.1 = 1;//вкл. прожектор
s1 = 0;}//сбросил флаг
}
//************************************************** ***
//************БЛОК ВЫКЛЮЧЕНИЯ ПРОЖЕКТОРА***************
if((read_adc(2) › i) && (s1 == 0)){//если света больше заданного порога
s1 = 2;//меняем флаг
s = 0;//секунды в ноль
}
if(s1 == 2){//условие сохраняется
if(s == 20){//отсчитали 20 сек
PORTB.1 = 0;//выкл. прожектор
s1 = 0;}//флаг сбросили
}
//************************************************** **** |
или вот еще идея была:
Код:
|
// Timer 0 output compare A interrupt service routine
interrupt [TIM0_COMPA] void timer0_compa_isr(void)
{
timer++;
if(timer==150) {s++;timer=0;}
if(s==5){PORTB.1==1;} else
TCNT0=0x00;
}
.....................
while (1)
{
if ((read_adc(2)‹409)){ // если напряжение на входе меньше порога
TCCR0B=0x04;//вкл.таймер
}
else{ // если напряжение на входе больше порога
TCCR0B = 0x00; // таймер ВЫКЛ.
s=0;}// сбросили секунды
if ((read_adc(2)›409)){ // если напряжение на входе меньше порога
TCCR0B=0x04;//вкл. таймер
}
else{ // если напряжение на входе больше порога
TCCR0B = 0x00; // таймер ВЫКЛ.
s=0;}// сбросили секунды
} |
Последний раз редактировалось neid_nnov; 11.09.2016 в 09:48.
|
|
|
|
16.09.2016, 19:17
|
|
Частый гость
Регистрация: 24.11.2006
Сообщений: 27
Сказал спасибо: 0
Сказали Спасибо 4 раз(а) в 4 сообщении(ях)
|
Re: Помогиге с кодом по датчику света - отключение, attiny13
Конечные автоматы. Автоматное программирование. Программные таймеры.
Цикл статей для ознакомления.
Состояния:
0 - Светло. Ждем затемнения. Если светло, выход. Если стемнело, запуск программного таймера на 20 с (но этого мало, вдруг облачко набежало, так что время нужно подбирать). Установка состояния 1.
1 - Ждем пока не выйдет заданное время. Если не вышло, выход. Если вышло, включаем прожектор. Установка состояния 2.
А тут засада. Стало светло, нужно репу чесать, чтобы прожектор не светил на фотодатчик.
2 - Ждем засветки. Если темно, то выход. Если светло, запуск программного таймера на 20 с (время нужно подбирать). Установка состояния 3.
3 - Ждем пока не выйдет заданное время. Если не вышло, выход. Если вышло, выключаем прожектор. Установка состояния 0.
|
|
|
|
20.09.2016, 21:36
|
|
Гражданин KAZUS.RU
Регистрация: 15.08.2010
Адрес: Днепр
Сообщений: 842
Сказал спасибо: 74
Сказали Спасибо 199 раз(а) в 174 сообщении(ях)
|
Re: Помогиге с кодом по датчику света - отключение, attiny13
Сообщение от neid_nnov
|
//*************БЛОК ВКЛЮЧЕНИЯ ПРОЖЕКТОРА*************
if((read_adc(2) ‹ i) && (s1 == 0)){//если
света меньше заданного порога и флаг сброшен
s1 = 1;//включаем флаг
s = 0;//секунды в ноль
}
if(s1 == 1){//если по прежнему сохраняется условие
if(s == 20){//насчитал больше 20 сек
PORTB.1 = 1;//вкл. прожектор
s1 = 0;}//сбросил флаг
} //************************************************** ***
|
Есть вопрос, если при затемнении установился флаг s1 и затемнение прошло до истечения 20 сек. где этот флаг сбросится? В таком случае включение произойдет после выдержки времени в любом случае. так же и с выключением.
PS. И не советую в условие вставлять функцию целиком. Функция read_acd() возвращает значение, ей нужно время на выполнение. Лучше занести результат измерения в какую-нибудь переменную, а потом ее сравнивать в условии.
Последний раз редактировалось МВА; 20.09.2016 в 22:17.
|
|
|
|
10.10.2016, 02:11
|
|
Почётный гражданин KAZUS.RU
Регистрация: 28.02.2010
Сообщений: 2,297
Сказал спасибо: 53
Сказали Спасибо 461 раз(а) в 392 сообщении(ях)
|
Re: Помогиге с кодом по датчику света - отключение, attiny13
Сообщение от МВА
|
Есть вопрос, если при затемнении установился флаг s1 и затемнение прошло до истечения 20 сек. где этот флаг сбросится? В таком случае включение произойдет после выдержки времени в любом случае. так же и с выключением.
PS. И не советую в условие вставлять функцию целиком. Функция read_acd() возвращает значение, ей нужно время на выполнение. Лучше занести результат измерения в какую-нибудь переменную, а потом ее сравнивать в условии.
|
Да там в read_acd()
// Wait for the AD conversion to complete
while ((ADCSRA & 0x10)==0);
Пока не родит не выйдет . Частота 150 Кгц Задержка....
Ну 100 микросекунд в АЦП побудет . Причём тут уже время выполнения ? Если речь про секунды идёт .Да и вообще непонятно - зачем куда-то заносить . Функция возвращает Результат .Вызываешь- берёшь- Пользуешься . На Прерываниях что-ли? .Нулевой Таймер - так это вообще без проблем , Ацп и не заметит , как и таймер проскочит ... Ничё не понимаю , в чём проблемы.
Последний раз редактировалось OlegNZH; 10.10.2016 в 02:34.
|
|
|
|
Ваши права в разделе
|
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения
HTML код Выкл.
|
|
|
Часовой пояс GMT +4, время: 13:37.
|
|