Вт мар 16, 2021 19:17:33
#define BUTTON_LUX_MEMORY PB1 //вход определения нажатой кнопоки 1
#define BUTTON_SYGNAL PB0 //вход определения нажатой кнопоки 0
GIFR |= (1<<INTF0) | (1<<PCIF); // сброс флагов прерывания
PCMSK |= (1<<BUTTON_LUX_MEMORY) | (1<<BUTTON_SYGNAL); //прерывания по входам PCINT0, PCINT1 (PB0, PB1)
GIMSK |= (1<<PCIE); //разрешаем внешние прерывание
ISR (PCINT0_vect) //обработка прерывания кнопки
{
GIMSK &= ~(1<<PCIE); //запрещаем прерывания
GIFR |= (1<<INTF0) | (1<<PCIF); // сброс флагов прерывания
TCCR0B = 0x00; //останоавливаем таймер
asm("wdr"); //сброс WDT
PORTB |= (1<<LED_OUT_PIN);
_delay_ms(500); //пауза 500 мС
if bit_is_clear (PINB,BUTTON_LUX_MEMORY)
{
MEM_value_LUX = read_adc(LUX_IN_PIN); eeprom_write_word(&LUX_MEM,MEM_value_LUX); //измеряем уровень освещенностиeeprom, записываем в
}
if bit_is_clear (PINB,BUTTON_SYGNAL)
{
NUM_SYGNAL+=1; while (NUM_SYGNAL == 7) {NUM_SYGNAL=0x01;} eeprom_write_byte(&SYGNAL_MEM,NUM_SYGNAL);
switch (NUM_SYGNAL)
{
case 1: SYGNAL=0xAA; break;
case 2: SYGNAL=0xCC; break;
case 3: SYGNAL=0xF0; break;
case 4: SYGNAL=0x63; break;
case 5: SYGNAL=0xD4; break;
default: SYGNAL=0xE6; break;
}
}
_delay_ms(500);
PORTB &= ~(1<<LED_OUT_PIN);
GIFR |= (1<<INTF0) | (1<<PCIF); // сброс флагов прерывания
TCCR0B |= (1<<CS02); // запуск таймера
Вт мар 16, 2021 20:43:59
GIMSK &= ~(1<<PCIE); //запрещаем прерывания
GIFR |= (1<<INTF0) | (1<<PCIF); // сброс флагов прерывания
Вт мар 16, 2021 20:51:34
#define LED_OUT_PIN PB3 //выход на светодиоды
Вт мар 16, 2021 21:23:33
а флаг прерывания сбрасывается по выходу.
Вт мар 16, 2021 21:25:42
Вт мар 16, 2021 21:30:00
Вт мар 16, 2021 21:33:59
Вт мар 16, 2021 21:51:40
Land писал(а):В тиньке13 PCINT на что реагирует? На смену уровня или на уровень?
Только на смену.
Land писал(а):аргументируйте, плз.
Land писал(а):Т.е. вы считаете, что в цикл падаю из-за чтения adc и записи в eeprom ? Ок, как рабочую версию приму, проверю. Спасибо
Вт мар 16, 2021 22:01:37
затрагивать скажем весь регистр PORTB?
В любом учебнике, во многих мануалах это написано - обработчик прерывания должен быть как можно более коротким.
Вт мар 16, 2021 22:09:27
затрагивать скажем весь регистр PORTB?
Вт мар 16, 2021 22:10:39
PB1 (MISO/AIN1/OC0B/INT0/PCINT1)
Ср мар 17, 2021 00:52:13
Ср мар 17, 2021 05:30:43
parovoZZ писал(а):Это кто-то придумал, а другие тупо скопипастили. Старые тиньки никак не предназначены для обработки прерывания вне его - флаги сбрасываются в прерывании, поэтому надо свои вводить, если обработчик пустой. Либо же лупом проверять флаги постоянно...Вообщем, костыльные микры...
Ср мар 17, 2021 07:49:49
Ср мар 17, 2021 08:49:19
.INCLUDE "tn13def.inc"
.CSEG
.ORG $000
RJMP START
.ORG $002
IN R22,PINB
RETI
;*************************************************
START:
CBI ACSR,ACD
SBI DDRB,2
SBI DDRB,3
LDI R16, 0b00000011
OUT PORTB, R16
LDI R16,1<<PCINT1|1<<PCINT0
OUT PCMSK, R16
LDI R16,1<<PCIE ;PCIE: разрешение прерывания при смене состояния лапы
OUT GIMSK, R16
OUT GIFR,R16
LDI R16,1<<SE
OUT MCUCR,R16
SEI
WAIT_PCINT:
SLEEP
ANDI R22,0b00000011
LSL R22
LSL R22
ORI R22,0b00000011
OUT PORTB,R22
RJMP WAIT_PCINT
.EXIT
Ср мар 17, 2021 09:37:58
Дело не в этом.
Ср мар 17, 2021 11:38:09
PORTB |= (1<<BUTTON_LUX_MEMORY) | (1<<BUTTON_SYGNAL); //входы кнопок (инициализация)
PORTB &= ~(1<<LED_OUT_PIN);
PORTB |= (1<<LED_OUT_PIN);
PORTB &= ~(1<<LED_OUT_PIN);
PORTB |= (1<<LED_OUT_PIN);
PORTB &= ~(1<<LED_OUT_PIN);
PORTB &= ~(1<<LED_OUT_PIN);
#define F_CPU 1200000UL // 1.2 MHz
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/eeprom.h>
#include <avr/sfr_defs.h>
#include <avr/sleep.h>
#include <util/delay.h>
// Declare your global variables here
#define LED_OUT_PIN PB3 //выход на светодиоды
#define Ubat_IN_PIN (1<<MUX0) //вход измерения напряжения батареи Ubat_IN_PIN ADC1D
#define BUTTON_LUX_MEMORY PB0 //вход определения нажатой кнопоки 1
#define BUTTON_SYGNAL PB1 //вход определения нажатой кнопоки 0
#define LUX_IN_PIN (1<<MUX1) //вход измерения уровня освещения LUX_IN_PIN ADC2D
#define ADC_VREF_TYPE ((0<<REFS0) | (0<<ADLAR)) //рефернесное напряжение для АЦП -- напряжение питания
uint16_t LUX_MEM EEMEM; //создаем метку адреса для значения освещенности в EEPROM
unsigned char SYGNAL_MEM EEMEM; //создаем метку адреса для сигнала мигания uint8_t
volatile unsigned char TIMER_CYCLE; //счетчик циклов таймера для мигания
volatile unsigned char SYGNAL=0xAA; //вид сигнала мигания по умолчанию
unsigned char NUM_SYGNAL=1; //номер сигнала мигания
//unsigned char BUTTON; //номер кнопки 1- запись уровня освещенности, 2 - изменение номера сигнала мигания
volatile unsigned char TIMER_SLEEP; //счетчик таймера сна
unsigned char mask; //локальная переменная маски
uint16_t value_LUX=0; //уровень освещенности с датчика
//uint16_t value_BUTTON=0; //нажатая кнопка
volatile uint16_t MEM_value_LUX; //сохраненное значение value_LUX
void key_func(void);
void sygnal_out(unsigned char);
unsigned char bat_level(void);
void LUX_level(void);
uint16_t read_adc(int);
// Pin change interrupt service routine
/*===================== ФУНКЦИИ =======================*/
void init(void)
{
// Declare your local variables here
// Port B initialization
DDRB |= (1<<LED_OUT_PIN); //выход
PORTB |= (1<<BUTTON_LUX_MEMORY) | (1<<BUTTON_SYGNAL); //входы кнопок
// INT0: Off
GIFR |= (1<<INTF0) | (1<<PCIF); // сброс флагов прерывания
PCMSK |= (1<<BUTTON_SYGNAL);//(1<<BUTTON_LUX_MEMORY) | (1<<BUTTON_SYGNAL); //прерывания по входам PCINT0, PCINT1 (PB0, PB1)
// Analog Comparator: Off
//ADCSRA |= (1<<ADPS0) | (1<<ADPS1);
ADCSRB &= ~(1<<ADTS2) & ~(1<<ADTS1) & ~(1<<ADTS0);
ADMUX |= (1<<AIN0D) | (1<<AIN1D); // Digital input buffer on AIN0: Off Digital input buffer on AIN1: Off
// ADC enabled
ADCSRA |= (1<<ADPS0) | (1<<ADPS1); // ADPS2=1, ADPS1=0,ADPS0=0 -- коэфф. делителя 8
ADMUX &= ~(1<<REFS0);
DIDR0 |= (1<<Ubat_IN_PIN) | (1<<LUX_IN_PIN); // | (0<<ADC3D); //ADC10 -- VCC, ADC20 -- LUX
// Timer/Counter 0 initialization
TCCR0A = 0x00;
TIMSK0 |= (1<<TOIE0); //прерывания по переполнению разрешены
TCNT0 = 0x00;
OCR0A = 0x00;
OCR0B = 0x00;
//MCUCR |= (1<<SM1); //режим POWER DOWN (1<<SE) Sleep Enable
// Watchdog timeout action: Reset + Interrupt
asm("wdr");
WDTCR |= (1<<WDCE) | (1<<WDE);
WDTCR |= (1<<WDTIF) | (1<<WDTIE) | (1<<WDP0) | (1<<WDP3); // | (1<<WDIE) разрешаем прерывание WDT, 8 сек.
MEM_value_LUX = eeprom_read_word(&LUX_MEM); //читаем из памяти сохраненное значение уровня освещенности
}
/*====================*/
uint16_t read_adc(int adc_input)
{
TCCR0B = 0; //останов таймера
ADMUX= adc_input | ADC_VREF_TYPE;
_delay_us(10); // Delay needed for the stabilization of the ADC input voltage
ADCSRA|=(1<<ADEN)|(1<<ADSC); //Запускаем преобразование
while ((ADCSRA & (1<<ADIF))==0); //Wait for the AD conversion to complete
ADCSRA|=(1<<ADIF); // сброс флага прерывания
ADCSRA &= ~(1<<ADEN); //останавливаем преобразование
return ADCW;
}
void sleepy(void)
{
cli();
TCCR0B = 0x00; //останоавливаем таймер
set_sleep_mode(SLEEP_MODE_PWR_DOWN); //устанавливаем режим сна Power Down
// set_sleep_mode(SLEEP_MODE_IDLE);
// WDTCR |= (1<<WDTIE); // //запускаем WDT
sleep_enable();
sei(); // Globally enable interrupts
}
unsigned char bat_level(void)
{
//модуль измерения и индикации низкого напряжения батареи
//PCMSK |= (1<<BUTTON_LUX_MEMORY) | (1<<BUTTON_SYGNAL); //разрешаем прерывания
TIMER_CYCLE = 0x00; //счетчик циклов таймера
uint16_t value_VCC=0; //определяем локальные переменные
value_VCC = read_adc(Ubat_IN_PIN); //измеряем напряжение батареи
if (value_VCC < 0x239) {SYGNAL=0xA8;} else //если напряжение ниже 1.6В (3.2В/2), то выставляем сигнал аларма, иначе
{NUM_SYGNAL = eeprom_read_byte(&SYGNAL_MEM); //читаем значение номера сигнала из EEPROM
switch (NUM_SYGNAL)
{
case 1: SYGNAL=0xAA; break;
case 2: SYGNAL=0xCC; break;
case 3: SYGNAL=0xF0; break;
case 4: SYGNAL=0x63; break;
case 5: SYGNAL=0xD4; break;
default: SYGNAL=0xE6; break;
}
}
return SYGNAL;
}
void LUX_level(void)
{
GIFR |= (1<<INTF0) | (1<<PCIF); // сброс флагов прерывания
GIMSK |= (1<<PCIE); //разрешаем внешние прерывание
value_LUX = read_adc(LUX_IN_PIN); //измеряем уровень освещенности
asm("wdr"); //сброс WDT
if (value_LUX > MEM_value_LUX)
{TIMER_SLEEP = 0x80; PORTB &= ~(1<<LED_OUT_PIN); sleepy(); //TIMER_SLEEP = 0x80 !!!!!!!!!!!!!!!!
while (TIMER_SLEEP)
{
sleep_cpu(); // спим
}
LUX_level(); //перепроверяем уровень освещенности
} //иначе -- спим 0x25 = 37 циклов таймера сна = 5 мин
//else {;}
{mask=0x80; TIMER_SLEEP = 0xFF;} // ,если темно, разрешаем прерывания, запускаем WDT ; sygnal_out(SYGNAL) TIMER_SLEEP = 0xFF !!!!!!!!!!!!!!!!
}
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
int main(void)
{
init();
LUX_level();
bat_level();
while (1)
{
TIFR0 |= (1<<TOV0); //сброс флага переполнения TIMR0
TCCR0B |= (1<<CS02); //прескалер /256 1.2Mhz/256=1171.875 Hz Period 0.055 sec.
TIMER_CYCLE = 0x00; //счетчик циклов таймера
sei();
//while (TIMER_SLEEP != 0)
while(1)
{
while (TIMER_CYCLE == 0) //если TMER_CYLE = 0, выполняем вложенное
{
if (SYGNAL & mask) //проверяем по маске бит выводимого сигнала логическое "или"
{
PORTB |= (1<<LED_OUT_PIN); //если в результате 1, выставляем 1
}
else
{
PORTB &= ~(1<<LED_OUT_PIN); //если в результате 0, выставляем 0
}
mask = mask >> 1; while (mask == 0) mask=0x80; //сдвинуть маску. обновить маску
TIMER_CYCLE = 0x03; //обновить счетчик таймера
GIFR |= (1<<INTF0) | (1<<PCIF); // сброс флагов прерывания
GIMSK |= (1<<PCIE); //разрешаем внешние прерывание
if (TIMER_SLEEP == 0) LUX_level(); else{}
}
}
}
}
// External Interrupt 0 service routine
ISR (PCINT0_vect) //обработка прерывания кнопки
{
GIMSK &= ~(1<<PCIE); //запрещаем прерывания
GIFR |= (1<<INTF0) | (1<<PCIF); // сброс флагов прерывания
TCCR0B = 0x00; //останоавливаем таймер
asm("wdr"); //сброс WDT
PORTB |= (1<<LED_OUT_PIN);
_delay_ms(250); //пауза 500 мС
if bit_is_clear (PINB,BUTTON_LUX_MEMORY)
{
PORTB &= ~(1<<LED_OUT_PIN);
//MEM_value_LUX = read_adc(LUX_IN_PIN); //измеряем уровень освещенности
//eeprom_write_word(&LUX_MEM,MEM_value_LUX); // записываем в память eeprom
}
if bit_is_clear (PINB,BUTTON_SYGNAL)
{
NUM_SYGNAL+=1; while (NUM_SYGNAL == 7) {NUM_SYGNAL=0x01;} eeprom_write_byte(&SYGNAL_MEM,NUM_SYGNAL);
switch (NUM_SYGNAL)
{
case 1: SYGNAL=0xAA; break;
case 2: SYGNAL=0xCC; break;
case 3: SYGNAL=0xF0; break;
case 4: SYGNAL=0x63; break;
case 5: SYGNAL=0xD4; break;
default: SYGNAL=0xE6; break;
}
}
_delay_ms(500);
PORTB &= ~(1<<LED_OUT_PIN);
GIFR |= (1<<INTF0) | (1<<PCIF); // сброс флагов прерывания
TCCR0B |= (1<<CS02); // запуск таймера
}
// Timer 0 overflow interrupt service routine
ISR (TIM0_OVF_vect)
{
--TIMER_CYCLE; // Декремент счетчика циклов таймера
}
ISR(WDT_vect) // Watchdog timeout interrupt service routine// обработка прерыания WDT
{
//cli();
MCUSR &= ~(1<<WDRF); //сбрасываем Watchdog Reset Flag
asm("wdr");
--TIMER_SLEEP; //декремент счетчика циклов таймера сна
WDTCR |= (1<<WDTIE); // запуск WDT
}
Ср мар 17, 2021 11:53:43
вы говорите, что в регистр GINSK нельзя писать через "или"?
Ср мар 17, 2021 12:16:18
Ср мар 17, 2021 13:31:08
Старые, это какие?