Доброго времени суток всем! Собираю таймер на меге8 вот этот: http://c2.at.ua/load/avr/tajmer_na_atmega8/17-1-0-25 прошивка с архива работает идеально,
но когда компилирую текст с исходника полученная прошивка не работает как должно, а именно не выводдится индикация секунд если остаётся менее часа до отключения
и нет сигнала на РС4 когда остаётся 20 секунд до завершения! Индикацию секунд я вывел и сигнал на РС4 тоже только не мигает светодиод ! Помогите!!
Вот собственно код исправленный мною;
/*
* tim.c
*
* Created: 04.04.2017 17:37:57
* Author: ARSEN
*/
#include <avr/io.h> // Most basic include files
#include <avr/interrupt.h> // Add the necessary ones
//#include <avr/signal.h> // here
//#define __AVR_ATmega8__
#include <avr/pgmspace.h>
#include <string.h>
//******************************************************************************
// Определение констант
//******************************************************************************
#define IND_PORT PORTD
#define IND_DDR DDRD
#define IND_COM PORTB
#define IND_CDDR DDRB
#define IND_PIN PINB
#define IND_CA1 PB1 // Левый индикатор
#define IND_CA2 PB2
#define IND_CA3 PB3
#define IND_CA4 PB4 // Правый
#define KEY_PORT PORTC
#define KEY_DDR DDRC
#define KEY_PIN PINC
#define KEY_HOURS PC0
#define KEY_MINUTES PC1
#define KEY_RUN PC2
#define KEY_RESET PC3
#define JUMPER PB0 // Джампер, определяющий работу после пропадания питания
#define CHECK_POWER PB5 // Вход для контроля наличия питания
#define SIGNAL_OUT PC4 // Выход для контрольного светодиода или пищалки
#define LOAD PC5 // Выход управления нагрузкой
// Значения для таймеров
#define T0_VALUE (255-78)
#define KEY_DEBOUNCE 100
// Флаги
#define f_WholeSec 0 // Флаг указывает, что отсчитана целая секунда.
// Используется для мигающей точки, переключается
// каждые 0.5 секунд
#define f_CountDown 1 // Флаг, указывающий на то, что происходит обратный
// отсчет. Используется для гашения ведущих нулей в
// индикации часов.
#define f_TimerRunning 2 // Флаг, указывающий на то, что таймер был запущен
#define f_Power 3 // Флаг наличия общего питания
#define f_Signal 4 // Флаг работы сигнализации (звуковой или световой)
#define IND_OA 1 // Общий анод
const unsigned char DIGITS_OA[] = {0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90};
//******************************************************************************
// Глобальные переменные
//******************************************************************************
//typedef struct {
// unsigned char Seconds;
// unsigned char Minutes;
// unsigned char Hours;
//} time;
//volatile time Time;
volatile unsigned char m_ucSecOnes = 0;
volatile unsigned char m_ucSecTens = 0;
volatile unsigned char m_ucMinOnes = 0;
volatile unsigned char m_ucMinTens = 0;
volatile unsigned char m_ucHrsOnes = 0;
volatile unsigned char m_ucHrsTens = 0;
volatile unsigned char sm_ucIndNum = 0;
volatile unsigned char m_ucFlags = 0;
volatile unsigned char ucKey_Run_Timeout = 0;
volatile unsigned char ucKey_Hours_Timeout = 0;
volatile unsigned char ucKey_Mins_Timeout = 0;
//******************************************************************************
// Прерывания
//******************************************************************************
// Прерывание по переполнению таймера Т0, здесь мы выводим часы и минуты на
// индикатор, а также опрашиваем кнопки.
ISR(TIMER0_OVF_vect, ISR_NOBLOCK){ // Разрешены вложенные прервания
volatile unsigned char ucTemp = 0; //
//volatile unsigned char ucKey_Run_Timeout;
TCNT0 = T0_VALUE; // Перезагрузка таймера
sm_ucIndNum++;
if (sm_ucIndNum > 3){
sm_ucIndNum = 0;
}
IND_COM &= ~((1<<IND_CA1)|(1<<IND_CA2)|(1<<IND_CA3)|(1<<IND_CA4));
IND_PORT = 0xFF;
// Во время работы таймера, когда идет отсчет, убираем ведущие ноли.
// Если пропало питание (очищен флаг питания) индикация отключена
switch (sm_ucIndNum){
case 0: {IND_COM |= (1<<IND_CA1); // Индикация десятков часов
ucTemp = DIGITS_OA[m_ucHrsTens];
break;}
case 1: {IND_COM |= (1<<IND_CA2); // Индикация единиц часов
ucTemp = DIGITS_OA[m_ucHrsOnes];
// Здесь мы мигаем точкой! если таймер запущен
if (m_ucFlags & (1 << f_TimerRunning))
if (m_ucFlags & (1 << f_WholeSec)){
ucTemp &= 0x7F;
}
break;}
case 2: {IND_COM |= (1<<IND_CA3); // Индикация десятков минут
ucTemp = DIGITS_OA[m_ucMinTens];
break;}
case 3: {IND_COM |= (1<<IND_CA4); // Индикация единиц минут
ucTemp = DIGITS_OA[m_ucMinOnes];
break;}
}
// А это мои изменения
if (m_ucFlags & (1 << f_TimerRunning)){ // Если таймер запущен
if(( m_ucHrsOnes<1)&&( m_ucHrsTens==0 )){ // и осталось менее одного часа,
switch (sm_ucIndNum){ // то на индикаторы выодятся минуты и секунды, индикатор приобретает форму формата ММ.СС
case 0: {IND_COM |= (1<<IND_CA1); // Индикация десятков минут
ucTemp = DIGITS_OA[m_ucMinTens];
break;}
case 1: {IND_COM |= (1<<IND_CA2); // Индикация единиц минут
ucTemp = DIGITS_OA[m_ucMinOnes];
// Здесь мы мигаем точкой!
if (m_ucFlags & (1 << f_TimerRunning)) // если таймер запушен
if (m_ucFlags & (1 << f_WholeSec)){ // то мигаем точкой
ucTemp &= 0x7F;
}
break;}
case 2: {IND_COM |= (1<<IND_CA3); // Индикация десятков секунд
ucTemp = DIGITS_OA[m_ucSecTens];
break;}
case 3: {IND_COM |= (1<<IND_CA4); // Индикация единиц секунд
ucTemp = DIGITS_OA[m_ucSecOnes];
break;}
}
}
}
if (IND_PIN & (1 << CHECK_POWER)){ // Если пропало питание
IND_PORT = ucTemp;
}
else{
IND_PORT = 0xFF; // отключаем индикацию
}
// Опрос кнопки Пуск/Пауза (KEY_RUN)
if((m_ucSecOnes==0)&&(m_ucSecTens==0)&&(m_ucMinOnes==0)&&(m_ucMinTens==0)&&(m_ucHrsOnes==0)&&(m_ucHrsTens==0)){
m_ucFlags &= ~(1 << f_CountDown);
m_ucFlags &= ~(1 << f_TimerRunning);
KEY_PORT &= ~(1 << LOAD);
KEY_PORT&=~(1 << SIGNAL_OUT);}
if (!(KEY_PIN & (1 << KEY_RUN))){
if (ucKey_Run_Timeout == 0){
// Установка флага работы таймера
// Этот флаг служит для блокировки кнопок и очищается
// в обработчике прерывания таймера Т2
m_ucFlags ^= (1 << f_CountDown);
m_ucFlags |= (1 << f_TimerRunning);
ucKey_Run_Timeout = 2*KEY_DEBOUNCE;
// Устанавливаем флаг питания
m_ucFlags |= (1 << f_Power);
// Переключаем нагрузку
if (m_ucFlags & (1 << f_CountDown)) KEY_PORT |= (1 << LOAD);
else KEY_PORT &= ~(1 << LOAD);
KEY_PORT&=~(1 << SIGNAL_OUT);
}
}
// Опрос кнопки настройки Часов
// Только если не установлен флаг работы таймера
if (!(m_ucFlags & (1 << f_TimerRunning))){
if (!(KEY_PIN & (1 << KEY_HOURS))){
if (ucKey_Hours_Timeout == 0){
m_ucHrsOnes ++;
if (m_ucHrsOnes > 9){
m_ucHrsOnes = 0;
m_ucHrsTens ++;
if (m_ucHrsTens > 9) m_ucHrsTens = 0;
}
ucKey_Hours_Timeout = KEY_DEBOUNCE;
}
}
}
// Опрос кнопки настройки минут
// Те же условия
if (!(m_ucFlags & (1 << f_TimerRunning))){
if (!(KEY_PIN & (1 << KEY_MINUTES))){
if (ucKey_Mins_Timeout == 0){
m_ucMinOnes ++;
if (m_ucMinOnes > 9){
m_ucMinOnes = 0;
m_ucMinTens++;
if (m_ucMinTens > 5) m_ucMinTens = 0;
}
ucKey_Mins_Timeout = KEY_DEBOUNCE;
}
}
}
// Опрос кнопки останова таймера
if (!(KEY_PIN & (1 << KEY_RESET))){
m_ucFlags &= ~(1 << f_CountDown); // Очистка флагов
m_ucFlags &= ~(1 << f_TimerRunning);
KEY_PORT&=~(1 << SIGNAL_OUT); // отключаем сигнал с РС4
m_ucHrsTens = 0; // это тоже мои изменения если нажать на сброс то очищаем и время
m_ucHrsOnes = 0;
m_ucMinTens = 0;
m_ucMinOnes = 0;
m_ucSecTens = 0;
m_ucSecOnes = 0;
// Отключаем нагрузку
KEY_PORT &= ~(1 << LOAD);
//
}
// Проверка наличия питания проводится только, если таймер в работе
if (m_ucFlags & (1 << f_TimerRunning)){
if (IND_PIN & (1 << CHECK_POWER)){ // power ok
// Проверяем состояние джампера
// и в зависимости от состояния флага питания делаем следующее
if (!(m_ucFlags & (1 << f_Power))){ // Если питание пропадало
if (IND_PIN & (1 << JUMPER)){
// Если джампер не замкнут Останавливаем отсчет
// нагрузка отключена
m_ucFlags &= ~(1 << f_CountDown);
KEY_PORT &= ~(1 << LOAD);
}
else{
// Если джампер замкнут на 0
// Продолжаем отсчет, включаем нагрузку
m_ucFlags |= (1 << f_CountDown);
KEY_PORT |= (1 << LOAD);
}
// Снова выставляем флаг, что с питанием все ок.
if (IND_PIN & (1 << CHECK_POWER))
m_ucFlags |= (1 << f_Power);
}
}
else{ //power fail
m_ucFlags &= ~(1 << f_Power);
// Отключаем нагрузку
KEY_PORT &= ~(1 << LOAD);
// Выставляем флаг паузы отсчета
m_ucFlags &= ~(1 << f_CountDown);
}
}
if (ucKey_Run_Timeout > 0) ucKey_Run_Timeout--;
if (ucKey_Hours_Timeout > 0) ucKey_Hours_Timeout--;
if (ucKey_Mins_Timeout > 0) ucKey_Mins_Timeout--;
}
// Таймер Т2 работает все время, останавливается или запускается
// только отсчет времени.
// Прерывание по переполнению таймера Т2
ISR(TIMER2_OVF_vect){
// сбрасываем счетный регистр таймера/счетчика T0
m_ucFlags ^= (1 << f_WholeSec); // Переключаем флаг
if (m_ucFlags & (1 << f_CountDown)){
if (m_ucFlags & (1<<f_WholeSec)){
if((m_ucSecOnes==7)&&( m_ucSecTens==0)&&( m_ucMinOnes==0)&&( m_ucMinTens==0)&&( m_ucHrsOnes==0)&&( m_ucHrsTens==0 ))
KEY_PORT|=(1 << SIGNAL_OUT); // здесь мы выводим сигнал на порт PC4 когда остаётся менее 7ми секунд до отключения
m_ucSecOnes --;
if (m_ucSecOnes > 9){
m_ucSecOnes = 9;
m_ucSecTens --;
if (m_ucSecTens > 5){
m_ucSecTens = 5;
m_ucMinOnes --;
if (m_ucMinOnes > 9){
m_ucMinOnes = 9;
m_ucMinTens --;
if (m_ucMinTens > 5){
m_ucMinTens = 5;
m_ucHrsOnes --;
if(m_ucHrsOnes > 9){
m_ucHrsOnes = 9;
m_ucHrsTens --;
if(m_ucHrsTens > 9){
// Здесь мы дошли до конца отсчета
m_ucHrsTens = 0;
m_ucHrsOnes = 0;
m_ucMinTens = 0;
m_ucMinOnes = 0;
m_ucSecTens = 0;
m_ucSecOnes = 0;
// Очищаем флаг отсчета
m_ucFlags &= ~(1 << f_CountDown);
m_ucFlags &= ~(1 << f_TimerRunning);
KEY_PORT &= ~(1 << LOAD); // отключаем нагрузку
KEY_PORT&=~(1 << SIGNAL_OUT); // отключаем сигнал РС4
}
}
}
}
}
}
}
}
};
//******************************************************************************
// Функции
//******************************************************************************
//******************************************************************************
// Main program
//******************************************************************************
int main(void) {
//***************************************************************************
// Инициализация периферии
//***************************************************************************
//int temp0, temp1;
// Настройка порта для сегментов индикатора
#ifdef IND_OA
IND_PORT = 0xFF;
#else
IND_PORT = 0x00;
#endif
IND_DDR = 0xFF;
// Настройка порта для общих выводов индикатора
IND_CDDR = 0x00;
IND_COM = 0x00;
IND_CDDR = (1<<IND_CA1)|(1<<IND_CA2)|(1<<IND_CA3)|(1<<IND_CA4);
IND_COM |= (1<<JUMPER)|(1<<CHECK_POWER)|(0<<IND_CA1)|(0<<IND_CA2)|(0<<IND_CA3)|(0<<IND_CA4);
// Настройка порта для кнопок
KEY_DDR &= ~((1<<KEY_HOURS)|(1<<KEY_MINUTES)|(1<<KEY_RUN)|(1<<KEY_RESET)); // input
KEY_DDR |= (1<<SIGNAL_OUT)|(1<<LOAD); // output
KEY_PORT |=(1<<KEY_HOURS)|(1<<KEY_MINUTES)|(1<<KEY_RUN)|(1<<KEY_RESET);
// Настройка таймера Т2, который работает в Асинхронном режиме
// и тактируется от часового кварца на 32768 Гц
///// Ждем пока не стабилизируется работа внешнего кварца
// for(temp0=0;temp0<0x0040;temp0++) // Wait for external clock crystal to stabilize
// {
// for(temp1=0;temp1<0xFFFF;temp1++);
// }
TIMSK &=~((1<<TOIE2)|(1<<OCIE2)); // Запрещаем TC2 прерывания
ASSR |= (1<<AS2); // Режим таймера - асинхронный
// тактирование от внешн. кварца (32,768kHz)
while (ASSR & (1 << TCN2UB)){};
TCNT2 = 0x00;
while (ASSR & (1 << TCR2UB)){};
TCCR2 = 0x04; //Делитель таймера / 64 для получения
// переполнения каждые 0.5 секунд
TIMSK |= (1<<TOIE2); //set 8-bit Timer/Counter2 Overflow Interrupt Enable
////////
// Настройка таймера Т0, который используется для динамической индикации
// и опроса кнопок. МК работает на частоте 1 МГц без внешнего кварца
// Загрузка регистра таймера Т0
TCNT0 = T0_VALUE;
// Разрешение прерываний по переполнению таймера Т0
TIMSK |= (1<<TOIE0);
// Пуск таймера Т0
TCCR0 = (0<<CS02)|(1<<CS01)|(1<<CS00);
// Разрешение глобальных прерываний
sei();
while(1) { // Infinite loop; define here the
asm ("nop"); // system behaviour
}
}
//******************************************************************************
// END of File
//********************