;********************************************************************** ; Filename: xxx.asm * ; Date: * ; File Version: * ; Author: Мазай * ;********************************************************************** list p=16f627 ; list directive to define processor #include ; processor specific variable definitions __CONFIG _CP_OFF & _WDT_OFF & _BODEN_ON & _PWRTE_ON & _XT_OSC & _MCLRE_OFF & _LVP_OFF ;***** ПЕРЕМЕННЫЕ ********************************************************************************* flag EQU 0x20 min_ml EQU 0x21 min_st EQU 0x22 hur_ml EQU 0x23 hur_st EQU 0x24 del_h EQU 0x25 del_l EQU 0x26 AdrNum EQU 0x27 ;Адрес выводимой цифры SelNum EQU 0x28 ;Знакоместо temp EQU 0x29 ;Временная переменная flags_I2C EQU 0x2A ;Флаги для работы с I2C rx_buff EQU 0x2B ;Приемный буфер (принятый байт) tx_buff EQU 0x2C ;Буфер для передачи (передаваемый байт) _n EQU 0x2D ;Счетчик бит при приеме/передаче addr EQU 0x2E ;Адрес назначения в устройстве (ведомой м/с) slave EQU 0x2F ;Адрес устройства (ведомой м/с) data_0 EQU 0x30 ;Первый (или единственный) байт данных data_1 EQU 0x31 ;Второй байт данных cl_sek EQU 0x32 ;Счетчик для получения 1 сек в прерывании min_0 EQU 0x33 ;Четыре переменных для хранения предустановленных кнопками часов и минут min_1 EQU 0x34 hur_0 EQU 0x35 hur_1 EQU 0x36 key_flag EQU 0x37 ;Переменная флагов для работы с кнопками w_temp EQU 0x70 ; variable used for context saving status_temp EQU 0x71 ; variable used for context saving ;Биты dp EQU 0x00 ;Флаг Точки SDA EQU 0x03 ;Вывод SDA SCL EQU 0x04 ;Вывод SCL ACK EQU 0x00 ;Флаг подтверждения приема устройством SLAVE (1 - принял, 0 - не принял) key_min EQU 0x00 ;Флаг изменения кнопками минут key_hur EQU 0x01 ;Флаг изменения кнопками часов ;*********** МАКРОСЫ ****************************************************************************** BANC_0 macro ;Включение Банка 0 bcf STATUS, RP0 endm BANC_1 macro ;Включение Банка 1 bsf STATUS, RP0 endm JNZ macro label ;Переход если не ноль btfss STATUS, Z goto label endm JZ macro label btfsc STATUS, Z goto label endm ;************* ПРОГРАММА ***************************************************************** ORG 0x000 ; processor reset vector goto main ; go to beginning of program ;************* ОБРАБОТКА ПРЕРЫВАНИЯ *************************************************************************** ORG 0x004 ;interrupt vector location bcf INTCON, T0IF ;Сброс флага прерывания по TMR0 ;Сохранение контента BANC_0 movwf w_temp movf STATUS,w movwf status_temp ;Считывание и преобразование времени movlw 0xD0 ;Чтение двух байт - минуты и часы movwf slave movlw 0x01 movwf addr call rd_2_byte movfw data_0 movwf min_ml movlw B'00001111' andwf min_ml, f movlw B'11110000' andwf data_0, f swapf data_0, f movfw data_0 movwf min_st movfw data_1 movwf hur_ml movlw B'00001111' andwf hur_ml, f movlw B'11110000' andwf data_1, f swapf data_1, f movfw data_1 movwf hur_st ;Индикация movlw B'00000000' ;Гасим индикатор movwf PORTB movfw AdrNum ;AdrNum > W movwf FSR ;W > FSR movfw INDF ;INDF > W (В INDF содержимое одного из регистров счетчика) addwf SelNum, w ;Совмещаем катод и код цифры btfsc SelNum, 6 ;Начало индикации точки! Проверяем разряд goto decp ;Если третий знак то вызов индикации точки bsf PORTA, RA1 ;Гасим точку если не третий знак goto $+6 ;И переходим на дальнейшую индикацию decp btfss flag, dp ;Точка включена? goto $+3 ;Нет, переходим на гашение точки bcf PORTA, RA1 ;Да, включаем точку goto $+2 ;Переходим на продолжение индикации bsf PORTA, RA1 ;Гасим точку movwf PORTB ;Выводим в порт код цифры и катод incf AdrNum, f ;Увеличиваем адрес регистра цифры счетчика на следующий bcf STATUS, C ;Сброс флага переноса rlf SelNum, f ;Сдвигаем влево указатель катода btfss STATUS, C ;Проверяем был ли перенос goto end_ind ;Анод не крайний левый. Конец индикации movlw min_ml ;Анод крайний левый. Готовимся к новому циклу индикации movwf AdrNum movlw B'00010000' movwf SelNum end_ind decfsz cl_sek, f ;Уменьшение счетчика секунд goto end_int ;До секунды не досчитали, выход из прерывания ;Досчитали до секунды movlw .244 ;Загрузка для следующего счета movwf cl_sek call read_key ;Опрос кнопок ;Выход из прерывания end_int movf status_temp,w ; retrieve copy of STATUS register movwf STATUS ; restore pre-isr STATUS register contents swapf w_temp,f swapf w_temp,w ; restore pre-isr W register contents retfie ; return from interrupt ;******************************************************************************************* ;Главная программа main bcf STATUS, RP1 ;Отключение банков 2 и 3 BANC_0 clrf INTCON ;Запрет прерываний movlw B'00000111' ;Отключение компараторов movwf CMCON BANC_1 clrf PIE1 ;Запрещение переферийных прерываний movlw B'11000011' movwf OPTION_REG ;Настройка предделителя movlw B'11111101' ;Настройка ПОРТА А (Пока выход только RA1 - точка) movwf TRISA clrf TRISB ;Настройка ПОРТА В (все выходы) BANC_0 clrf PORTA ;Иннициализация портов и гашение индикатора movlw B'00000000' movwf PORTB call delay_10ms ;Начальная задержка ;Иннициализация часов movlw 0xD0 ;Заносим адрес устройства movwf slave ;в соответствующую переменную movlw 0x00 ;Заносим адрес в устройстве movwf addr ;в соответствующую переменную call rd_byte ;Читаем (по адресу 0х00 в DS1307 хранятся секунды. Лог.1 в 7 разряде секунд показывает, что генератор выключен, а значит было отключение DS1307 btfss data_0, 7 ;Проверяем единицу в 7 разряде goto power_ok ;Нет. Там ноль. Резервное питание не пропадало movlw 0xD0 ;Питание пропадало. Начинаем иннициализацию. Заносим адрес устройства movwf slave ;в соответствующую переменную movlw 0x00 ;Заносим адрес в устройстве movwf addr ;в соответствующую переменную movlw 0x00 ;Заносим данные movwf data_0 ;в соответствующую переменную call wr_byte ;Передаем байт - Обнуляется регистр секунд и включается генератор nop movlw 0xD0 ;Заносим адрес устройства movwf slave ;в соответствующую переменную movlw 0x01 ;Заносим адрес в устройстве movwf addr ;в соответствующую переменную movlw 0x00 ;Заносим данные movwf data_0 ;в соответствующую переменную call wr_byte ;Передаем байт - Обнуляется регистр минут nop movlw 0xD0 ;Заносим адрес устройства movwf slave ;в соответствующую переменную movlw 0x02 ;Заносим адрес в устройстве movwf addr ;в соответствующую переменную movlw 0x00 ;Заносим данные movwf data_0 ;в соответствующую переменную call wr_byte ;Передаем байт - Обнуляется регистр часов (одновременно устанавливается 24 часовой формат (6-й в лог.0) nop movlw 0xD0 ;Заносим адрес устройства movwf slave ;в соответствующую переменную movlw 0x07 ;Заносим адрес (управляющий регистр) в устройстве movwf addr ;в соответствующую переменную movlw 0x90 ;Заносим данные movwf data_0 ;в соответствующую переменную call wr_byte ;Передаем байт - устанавливается частота 1 Гц. и включается разрешение ее генерации nop power_ok ;Конец иннициализации часов clrf min_ml ;Обнуляем ячейки счетчика clrf min_st clrf hur_ml clrf hur_st movlw min_ml ;Адрес min_ml в w movwf AdrNum movlw B'00010000' ;Начальное знакоместо (младший разряд) movwf SelNum movlw .244 ;Загрузка начального значения в счетчик секунды movwf cl_sek clrf TMR0 ;Сброс таймера bcf INTCON, T0IF ;Сброс флага прерывания по TRM0 bsf INTCON, T0IE ;Разрешение прерывания по TRM0 bsf INTCON, GIE ;Общее разрешение прерываний lab1 btfsc PORTA, RA5 ;Установка флага состояния точки в соответствии с RA5 goto $+3 ;RA5 в "1", устанавливаем "1" bcf flag, dp ;RA5 в "0", устанавливаем "0" goto $+2 ;Переходим дальше bsf flag, dp ;Устаналиваем "1" goto lab1 ;Циклимся на опросе состояния RA5 ;***************************** ПОДПРОГРАММЫ ********************************************** ;Задержка ~ 10 мсек delay_10ms BANC_0 movlw .14 movwf del_h movlw .74 movwf del_l del_loop decfsz del_l, f goto del_loop decfsz del_h, f goto del_loop return ;************** ПОДПРОГРАММА ОПРОСА КЛАВИШ УСТАНОВКИ ВРЕМЕНИ *************************************** read_key BANC_0 movfw min_ml ;Текущее время в необходимые переменные movwf min_0 movfw min_st movwf min_1 movfw hur_ml movwf hur_0 movfw hur_st movwf hur_1 ;Опрос кнопок btfsc PORTA, RA2 ;Нажата кнопка минуты? goto mn_key ;Нет, выход из опроса кнопки МИНУТЫ goto m_key ;Да. Переход на обработку mn_key bcf key_flag, key_min ;Сброс флага индицируя, что кнопка минуты не нажата goto hur_key ;Переход на опрос кнопки часов m_key bsf key_flag, key_min ;Установка флага индицируя, что кнопка минуты нажата movfw min_0 ;Кнопка нажата. Увеличение минут sublw .9 ;min_ml = 9? JZ st_count ;Да. Переходим к десяткам минут incf min_0, f ;Нет. Увеличиваем счетчик на 1 goto hur_key ;и выходим из опроса кнопки МИНУТЫ st_count movfw min_1 ;Подготовка к проверке десятков минут sublw .5 ;min_st = 5? JZ end_count ;Да. Счетчик макс (59)! Переходим к обнулению clrf min_0 ;Нет. Обнуляем единицы минут incf min_1, f ;и увеличиваем на единицу десятки минут goto hur_key ;и выходим из опроса кнопки МИНУТЫ end_count clrf min_0 ;Счетчик макс - 59. Обнуляем разряд единиц минут clrf min_1 ;и разряд десятков минут hur_key btfsc PORTA, RA0 ;Нажата кнопка ЧАСЫ? goto hn_key ;Нет, выход из опроса кнопки ЧАСЫ goto h_key ;Да. Переход на обработку hn_key bcf key_flag, key_hur ;Сброс флага индицируя, что кнопка часов не нажата goto end_key ;Переход на окончание опроса h_key bsf key_flag, key_hur ;Установка флага индицируя, что кнопка часов нажата movfw hur_1 ;Кнопка нажата. Проверяем разряд Десятков (0 и 1 или 2) sublw .2 ;hur_st=2? JZ count_3 ;Да. Обрабатываем "Единицы только до 3" movfw hur_0 ;Нет. Проверяем единицы на макс. 9 sublw .9 ;hur_ml=9? JZ hst_count ;Да. Переходим к увеличению десятков и обнулению единиц incf hur_0, f ;Нет. Увеличиваем значение единиц часов goto end_key ;Переходим на конец опроса кнопки count_3 movfw hur_0 ;Готовимся проверить единицы часов на 3 sublw .3 ;hur_ml=3? JZ hur_clear ;Да. В счетчиках часов макс. - 23. Переходим на обнуление incf hur_0, f ;Нет. Увеличиваем значение единиц часов goto end_key ;Переходим на конец опроса кнопки hst_count clrf hur_0 ;Обнуляем единицы часов incf hur_1 ;Увеличиваем десятки часов goto end_key hur_clear clrf hur_0 ;Счетчик макс - 23. Обнуляем разряд единиц часов clrf hur_1 ;и разряд десятков часов end_key movfw key_flag ;Проверка на наличие установленных флагов нажатия кнопок JZ e_k ;Флаги не установлены, выходим movlw B'00001111' ;Флаг(и) установлены. Было нажатие кнопки(ок). Обрабатываем andwf min_0, f ;Обнуляем на всякий случай старшую тетраду andwf min_1, f andwf hur_0, f andwf hur_1, f swapf min_1, f swapf hur_1, f movfw min_1 addwf min_0, f movfw hur_1 addwf hur_0, f bcf hur_0, 6 ;На всякий пожарный сбрасываем принудительно бит 12/24 режима movfw min_0 ;Перемещаем в переменные для передачи по I2C movwf data_0 movfw hur_0 movwf data_1 movlw 0xD0 movwf slave movlw 0x01 movwf addr call wr_2_byte ;Записываем новые значения e_k return ;**************************************************************************************************************** ;******************** ПОДПРОГРАММЫ I2C ************************************************************************** ; Установка высокого уровня производится переводом вывода на ВХОД (резисторы на шине обеспечивают лог.1) ; Установка низкого уровня производится записью в соответствующий вывод 0 у установке этого вывода на ВЫХОД ;**************************************************************************************************************** ;*********************** Подпрограммы сверхвысокого (интерфейс) уровня ****************************************** rd_byte ;Чтение одного байта ;Входные данные: slave - адрес устройства ; addr - адрес в устройстве ;Выходные данные: data_0 - считанный байт movfw slave ;Перенос адреса устройства movwf tx_buff ;в буфер передачи bcf tx_buff, 0 ;Устанавливаем режим WRITE call start ;Генерируем условие СТАРТ call write_byte ;Передаем call read_ack ;Получаем подтверждение movfw addr ;Перенос адреса в устройстве movwf tx_buff ;в буфер передачи call write_byte ;Передаем call read_ack ;Получаем подтверждение call start ;Повторно генерируем условие СТАРТ movfw slave ;Перенос адреса устройства movwf tx_buff ;в буфер передачи bsf tx_buff, 0 ;Устанавливаем режим READ call write_byte ;Передаем call read_ack ;Получаем подтверждение call read_byte ;Получаем байт call write_noack ;НЕ подтверждаем получение чтоб прекратить передачу устройством call stop ;Генерируем условие СТОП movfw rx_buff ;Перемещаем полученный байт movwf data_0 ;в выходную переменную return rd_2_byte ;Чтение двух байта ;Входные данные: slave - адрес устройства ; addr - адрес в устройстве ;Выходные данные: data_0 - первый считанный байт ; data_1 - второй считанный байт movfw slave ;Перенос адреса устройства movwf tx_buff ;в буфер передачи bcf tx_buff, 0 ;Устанавливаем режим WRITE call start ;Генерируем условие СТАРТ call write_byte ;Передаем call read_ack ;Получаем подтверждение movfw addr ;Перенос адреса в устройстве movwf tx_buff ;в буфер передачи call write_byte ;Передаем call read_ack ;Получаем подтверждение call start ;Повторно генерируем условие СТАРТ movfw slave ;Перенос адреса устройства movwf tx_buff ;в буфер передачи bsf tx_buff, 0 ;Устанавливаем режим READ call write_byte ;Передаем call read_ack ;Получаем подтверждение call read_byte ;Получаем байт call write_ack ;Выдаем подтверждение movfw rx_buff ;Перемещаем первый полученный байт movwf data_0 ;в выходную переменную call read_byte ;Получаем байт call write_noack ;НЕ подтверждаем получение чтоб прекратить передачу устройством call stop ;Генерируем условие СТОП movfw rx_buff ;Перемещаем второй полученный байт movwf data_1 ;в выходную переменную return wr_byte ;Запись одного байта ;Входные данные: slave - адрес устройства ; addr - адрес в устройстве ; data_0 - записываемый байт movfw slave ;Перенос адреса устройства movwf tx_buff ;в буфер передачи bcf tx_buff, 0 ;Устанавливаем режим WRITE call start ;Генерируем условие СТАРТ call write_byte ;Передаем call read_ack ;Получаем подтверждение movfw addr ;Перенос адреса в устройстве movwf tx_buff ;в буфер передачи call write_byte ;Передаем call read_ack ;Получаем подтверждение movfw data_0 ;Переносим передаваемый байт movwf tx_buff ;в буфер передачи call write_byte ;Передаем call read_ack ;Получаем подтверждение call stop ;Генерируем условие СТОП return wr_2_byte ;Запись двух байта ;Входные данные: slave - адрес устройства ; addr - адрес в устройстве ; data_0 - первый записываемый байт ; data_1 - второй записываемый байт movfw slave ;Перенос адреса устройства movwf tx_buff ;в буфер передачи bcf tx_buff, 0 ;Устанавливаем режим WRITE call start ;Генерируем условие СТАРТ call write_byte ;Передаем call read_ack ;Получаем подтверждение movfw addr ;Перенос адреса в устройстве movwf tx_buff ;в буфер передачи call write_byte ;Передаем call read_ack ;Получаем подтверждение movfw data_0 ;Переносим первый передаваемый байт movwf tx_buff ;в буфер передачи call write_byte ;Передаем call read_ack ;Получаем подтверждение movfw data_1 ;Переносим второй передаваемый байт movwf tx_buff ;в буфер передачи call write_byte ;Передаем call read_ack ;Получаем подтверждение call stop ;Генерируем условие СТОП return ;*********************** Подпрограммы высокого уровня *********************************************************** start ;Генерирование начального условия START ;high_sda BANC_1 bsf TRISA, SDA ;Вывод SDA как вход nop nop nop nop ;high_scl bsf TRISA, SCL ;Вывод SCL как вход nop nop nop nop ;low_sda BANC_0 bcf PORTA, SDA ;Обнуление бита SDA в защелке PORTA BANC_1 bcf TRISA, SDA ;Вывод SDA как выход nop nop nop nop ;low_scl BANC_0 bcf PORTA, SCL ;Обнуление бита SCL в защелке PORTA BANC_1 bcf TRISA, SCL ;Вывод SCL как выход nop nop nop nop BANC_0 return stop ;Генерирование завершающего условия STOP BANC_0 bcf PORTA, SCL ;Обнуление бита SCL в защелке PORTA BANC_1 bcf TRISA, SCL ;Вывод SCL как выход nop nop nop nop BANC_0 bcf PORTA, SDA ;Обнуление бита SDA в защелке PORTA BANC_1 bcf TRISA, SDA ;Вывод SDA как выход nop nop nop bsf TRISA, SCL ;Вывод SCL как вход nop nop nop nop nop bsf TRISA, SDA ;Вывод SDA как вход nop nop nop BANC_0 return read_byte ;Чтение байта из SLAVE устройства ;Выходной параметр: Прочитанный байт в переменной rx_buff clrf rx_buff ;Очистка буфера приема movlw .8 ;Загрузка числа бит в байте movwf _n ;в счетчик BANC_1 bsf TRISA, SDA ;Вывод SDA как вход in_bit BANC_1 nop bsf TRISA, SCL ;Вывод SCL как вход(Начало стробирующего импульса) nop nop BANC_0 btfss PORTA, SDA ;Проверка уровня на выводе SDA goto read_0 ;На выводе 0. Переход на обработку приема бита имеющего уровень лог.0 goto read_1 ;На выводе 1. Переход на обработку приема бита имеющего уровень лог.1 read_0 bcf STATUS, C ;Установка 0 в бите переноса rlf rx_buff, f ;Задвигание бита переноса в буфер приема goto cont_read read_1 bcf STATUS, C ;Установка 0 в бите переноса rlf rx_buff, f ;Задвигание его в буфер приема incf rx_buff, f ;и изменение его на лог.1 (зачем так сложно, я не понял, но так было в примере. Почему нельзя было поставить бит переноса сразу в 1 и задвинуть в буфер?) cont_read bcf PORTA, SCL ;Обнуление бита SCL в защелке PORTA(Заканчиваение импульса синхронизации) BANC_1 bcf TRISA, SCL ;Вывод SCL как выход BANC_0 decfsz _n, f ;Уменьшение счетчика битов goto in_bit ;Биты не кончились, переход на новый прием бита return write_byte ;Запись байта в SLAVE устройство ;Входной параметр: Передаваемый байт в переменной tx_buff movlw .8 ;Загрузка числа бит в байте movwf _n ;в счетчик out_bit bcf STATUS, C ;Установка 0 в бите переноса rlf tx_buff, f ;Задвигание бита в бит переноса btfss STATUS, C ;Проверка на значение передаваемого бита goto write_0 ;Передаваемый бит в 0. Переход на передачу бита имеющего уровень лог.0 goto write_1 ;Передаваемый бит в 1. Переход на передачу бита имеющего уровень лог.1 write_0 bcf PORTA, SDA ;Обнуление бита SDA в защелке PORTA BANC_1 bcf TRISA, SDA ;Вывод SDA как выход(Установка вывода SDA в 0) nop nop bsf TRISA, SCL ;Вывод SCL как вход nop nop BANC_0 bcf PORTA, SCL ;Обнуление бита SCL в защелке PORTA BANC_1 bcf TRISA, SCL ;Вывод SCL как выход nop nop bsf TRISA, SDA ;Вывод SDA как вход (отключение от линии) BANC_0 goto cont_write write_1 BANC_1 bsf TRISA, SDA ;Вывод SDA как вход(Установка вывода SDA в 1) nop nop bsf TRISA, SCL ;Вывод SCL как вход nop nop BANC_0 bcf PORTA, SCL ;Обнуление бита SCL в защелке PORTA BANC_1 bcf TRISA, SCL ;Вывод SCL как выход BANC_0 cont_write decfsz _n, f ;Уменьшение счетчика передаваемых бит goto out_bit ;Биты не кончились. Переход на передачу следующего бита return ;*********************** Подпрограммы среднего уровня *********************************************************** read_ack ;Чтение бита ACK для получения подтверждения приема устройством SLAVE ;Выходной параметр: Значение бита АСК в переменной flags_I2C BANC_1 bsf TRISA, SDA ;SDA как вход nop nop bsf TRISA, SCL ;Вывод SCL как вход (Начинаем импульс синхронизации) nop BANC_0 btfss PORTA, SDA ;Читаем SDA, и если АСК = 0 bsf flags_I2C, ACK ;то устанавливаем флаг АСК в 1, что значит SLAVE устройство получило байт btfsc PORTA, SDA ;Читаем SDA, и если ACK = 1 bcf flags_I2C, ACK ;то устанавливаем флаг АСК в 0, что значит SLAVE устройство не получило байт bcf PORTA, SCL ;Обнуление бита SCL в защелке PORTA BANC_1 bcf TRISA, SCL ;Вывод SCL как выход(Заканчиваем импульс синхронизации) BANC_0 nop nop return write_ack ;Выдача бита АСК как лог.0 - подтверждение приема устройством MASTER BANC_0 bcf PORTA, SDA ;Обнуление бита SDA в защелке PORTA BANC_1 bcf TRISA, SDA ;Вывод SDA как выход nop nop nop bsf TRISA, SCL ;Вывод SCL как вход nop nop BANC_0 bcf PORTA, SCL ;Обнуление бита SCL в защелке PORTA BANC_1 bcf TRISA, SCL ;Вывод SCL как выход BANC_0 return write_noack ;Выдача бита АСК как лог.1 - нет подтверждения приема устройством MASTER (применяется в конце передачи последнего бита перед выдачей STOP) BANC_1 bsf TRISA, SDA ;Вывод SDA как вход nop nop nop bsf TRISA, SCL ;Вывод SCL как вход nop nop BANC_0 bcf PORTA, SCL ;Обнуление бита SCL в защелке PORTA BANC_1 bcf TRISA, SCL ;Вывод SCL как выход BANC_0 return ;*************************** Ячейки ПЗУ *********************************************** ORG 0x2100 de "CLOCK v 1.0. Mazay (c) 2003. E-mail - mazay@lek.ru" END ; directive 'end of program'