Спасибо за ответ. Я сейчас читаю-перевожу книгу Peter H. Anderson - PIC16F877x Tutorial by Example и моделирую схему, представленные в ней в Proteus. Ниже представлен текст программы с комментариями (hex-файл создавался с помощью компилятора CCS). Да, я действительно использовал модель CRYSTAL и Таймер 1 не тактировался вообще - т.е. переполнений не было. Эта программа заточена под 4-хстрочный дисплей, но в Proteus я использовал 2-хстрочный. В железе эта программа работает.
// Программа TIMER1_1.C
//Используется таймер TMR1, который тактируется внешним кристаллом 32.768 кГц
// с выводов T1OSC0 и T1OSC1.
// На экране ЖКИ отображается время в формате "часы-минуты-секунды".
// Разработано, Peter H. Anderson, Baltimore, MD, Dec, '00
#case // Компилятор чувствителен к регистру букв
#device PIC16F877 *=16 // Используем МК PIC16F877
#include ‹defs_877.h› // Описание регистров и битов PIC16F877
#include ‹lcd_out.h› // Прототипы функций для работы с ЖКИ
#define TRUE !0 // Теперь TRUE – это 1
#define FALSE 0 // Теперь FALSE – это 0
struct TM // Объявляем структурный тип ТМ
{
byte hr; // 8 бит для хранения часов
byte mi; // 8 бит для хранения минут
byte se; // 8 бит для хранения секунд
};
void blip_tone(void);
void increment_time(struct TM *t); // Структурный тип передается по ссылке
byte timer1_int_occ;//Глобальная переменная – видна во всех функциях программы
void main(void) // Начало программы
{ // Начало main
long elapsed_t; // 32 бита для хранения истекшего времени
struct TM t; // Создаем переменную типа структуры ТМ
pcfg3=0; pcfg2=1; pcfg1=0; pcfg0=0;//Режим АЦП 3/0 – 3 аналог. входа RA3, RA1, RA0
lcd_init(); // Инициализация ЖКИ
portd0 = 0;// Выводим на контакт спикера RD0 лог. 0
trisd0 = 0; // RD0 – режим вывод
// Настраиваем таймер TMR2
PR2 = 250; // Время переполнения 250*4 мксек =1 мсек (при Fosc=4 МГц)
// Коэффициент деления постделителя TMR2 равен 1:1
toutps3 = 0; toutps2 = 0; toutps1 = 0; toutps0 = 0;
// Коэффициент деления предделителя TMR2 равен 1:4
t2ckps1 = 0; t2ckps0 = 1;
// Настраиваем таймер TMR1
t1oscen = 1;// Разрешаем тактирование таймера от внешнего кварца
tmr1cs = 1;// Выбираем внешнее тактирование для этого таймера
t1ckps1 = 0; t1ckps0 = 0;// Коэффициент деления предделителя TMR1 равен 1:1
tmr1if=0;//Чтобы не было ложного входа в обработчик – сбрасываем флаг от TMR1
TMR1L = 0x00; // Инициализируем таймер числом 0х8000 (3276
TMR1L = 0x80;
tmr1ie = 1; // Разрешаем прерывания по переполнению таймера TMR1
peie = 1; // Разрешаем прерывания от периферийных устройств
gie = 1; // Глобальное разрешение прерываний
timer1_int_occ = FALSE; // Глобальная переменная равна 0 (FALSE)
elapsed_t = 0; // Начинаем отсчет времени с 0
t.hr = 0; t.mi = 0; t.se = 0; // Минуты=секунды=часы=0
tmr1on = 1; // Включаем таймер TMR1 – с этого момента он начинает считать
//В программе можно использовать 4-хстрочный индикатор – он более информативен
lcd_clr_line(2); // Очищаем строку 3 индикатора и …
printf(lcd_char, "Impress the spouse"); // выводим строку Impress the spouse
lcd_clr_line(3); // Очищаем строку 4 и …
printf(lcd_char, "with a personal msg!"); // выводим строку with a personal msg!
while(1) // Бесконечный цикл
{ // Начало while
if (timer1_int_occ) // Если глоб перем. timer1_int_occ равна 1, то…
{ // Начало if
timer1_int_occ = FALSE; // Опять обнуляем глоб. перем. timer1_int_occ
++elapsed_t; // Инкрементируем прошедшее время
increment_time(&t);//Передаем адрес структурной переменной в increment_time()
lcd_clr_line(0); // Очищаем строку 0 индикатора и…
printf(lcd_char, "%ld ", elapsed_t); // выводим истекшее время
lcd_clr_line(1); // Очищаем строку 1 индикатора и…
lcd_dec_byte(t.hr, 2); // выводим кол-во часов в 2х разрядах
lcd_char(':'); // Выводим «:»
lcd_dec_byte(t.mi, 2); // выводим кол-во минут в 2х разрядах
lcd_char(':'); // Выводим «:»
lcd_dec_byte(t.se, 2); // И выводим кол-во секунд в 2х разрядах
blip_tone(); // Вызываем blip_tone()
} // Конец if
} // Конец while
} // Конец main
void blip_tone(void)
{ // Начало blip_tone
tmr2ie = 1; // Разрешаем прерывания от таймера TMR2
peie = 1; // Разрешаем прерывания от периферийных устройств
tmr2on = 1; // Включаем таймер TMR2
gie = 1; // Глобальное разрешение прерываний
delay_ms(200); // Пауза 200 мсек – за это время таймер TMR2 переполнится 200 раз
tmr2ie = 0; // Запрещаем прерывания от таймера TMR2
tmr2on = 0; // Выключаем таймер TMR2
} // Конец blip_tone
void increment_time(struct TM *t) // Функция считает время в формате «ч-м-с»
{ // Начало функции
++t-›se; // Инкрементируем секунды
if (t-›se › 59) // Если секунд больше 59, то…
{ // Начало if1
t-›se = 0; // обнуляем счетчик секунд и…
++t-›mi; // инкрементируем минуты
if (t-›mi › 59) // Если минут больше 59, то…
{ // Начало if2
t-›mi = 0; // обнуляем минуты и…
++t-›hr; // инкрементируем часы
if (t-›hr › 23) // Если часов больше 23, то…
{ // Начало if3
t-›hr = 0; // обнуляем часы
} // Конец if3
} // Конец if2
} // Конец if1
} // Конец функции
#int_timer1
timer1_int_handler(void) // Обработчик прерывания от таймера TMR1
{
timer1_int_occ = TRUE; // Разрешаем вход в блок if функции main
TMR1H = 0x80; // Инициализируем таймер TMR1
}
#int_timer2
timer2_int_handler(void)
{
portd0 = !portd0; // Инвертируем бит RD0 – динамик щелкает…
}
#include ‹lcd_out.c›