По просьбе одного из комментаторов моего блога решил выложить вот такой простой пример. Микроконтроллер – ATmega88A(или просто ATmega88). Микроконтроллер просто читает время/дату из RTC и записывает на дисплей.
Итак, для начала схема(модель в Proteus – прилагается, кликните по картинке, чтобы посмотреть в полный размер):
.include "m88Adef.inc" #define F_CPU (8000000) ;========================================================================= .def temp=r16 .def temp1=r17 .def temp2=r18 .def temp3=r19 ;Определения регистров ;========================================================================= .macro OUTI ldi r16,@1 out @0,r16 .endm ;Макрос для вывода данных в порт/регистр(очень удобный!). ;========================================================================= .dseg ;Переменные в оперативной памяти Hours: .byte 1; 1 байт под часы Minutes: .byte 1; 1 байт под минуты Days: .byte 1; 1 байт под дни Month: .byte 1; 1 байт под месяц Weekday: .byte 1; 1 байт для дня недели Year: .byte 2; Год в 1 байт не помещается, поэтому 2 ;========================================================================= .cseg ;Тут начинается код OUTI SPL, low(RAMend); Инициализация стека OUTI SPH, High(RAMEND) rcall rtc_start;Запуск хода часов. rcall lcd_init;Инит LCD дисплея ldi r16,0x40;Будем писать начиная со второй строки rcall LCD_SetAddressDD ldi r16, 'R' ;Выводим на дисплей строчку с rcall LCD_WriteData; адресом моего сайта :))) ldi r16, 'a' rcall LCD_WriteData ldi r16, 'd' rcall LCD_WriteData ldi r16, 'i' rcall LCD_WriteData ldi r16, 'o' rcall LCD_WriteData ldi r16, 'e' rcall LCD_WriteData ldi r16, 'l' rcall LCD_WriteData ldi r16, 'e' rcall LCD_WriteData ldi r16, 'k' rcall LCD_WriteData ldi r16, 't' rcall LCD_WriteData ldi r16, 'r' rcall LCD_WriteData ldi r16, '.' rcall LCD_WriteData ldi r16, 'r' rcall LCD_WriteData ldi r16, 'u' rcall LCD_WriteData ;========================================================================= main: ;Главный цикл ldi r16,0;Пишем начиная с первой строки и первого знакоместа rcall lcd_setaddressdd rcall rtc_get_time;Читаем время из DS1307 lds temp,hours;Вытаскиваем значение часов из оперативки rcall vivod;Выводим на дисплей ldi r16,0x3A;Двоеточие rcall LCD_WriteData ;Выводим минуты на дисплей так-же, как и часы ;-------------------------------------- lds temp,minutes rcall vivod ;-------------------------------------- rcall rtc_get_date;Читаем дату ldi r16,6; Пишем, начиная с 6 знакоместа rcall lcd_setaddressdd ;Вывод числа lds temp,days rcall vivod ldi r16,'/';Слеш rcall lcd_writeData ;Вывод месяца lds temp,month rcall vivod ldi r16,'/';Слеш rcall lcd_writeData ;Выводим первые 2 разряда года - 20 ldi temp,'2' rcall LCD_WriteData ldi r16,'0' rcall LCD_WriteData ;Вывод года lds temp,year+1 rcall vivod ;Зацикливаемся rjmp main .include "soft-iic.asm";Модуль для реализации программного I2C .include "DS1307.asm"; Библиотека для DS1307 .include "hd44780.asm"; Библиотека LCD ;----------------------------------------------- ; DEC TO 2DEC ;----------------------------------------------- ; Процедура делает из десятичного (0......99) числа ; Два десятичных числа - единицы и десятки ;Исходное число помещаем в r16 ;На выходе получаем в r16 - младший байт, а в r17 - старший. Hex2dec: SUBI r16,100 BRCC Hex2dec LDI r17,10 _bcd2: DEC r17 SUBI r16,-10 BRCS _bcd2 Ret ;========================================================================= vivod: ;Вывод данных на дисплей. Упаковал в процедуру для сокращения кода. rcall hex2dec; Раскладываем на 2 разряда ; Как именно - смотрите в комментариях к процедуре push r16; Сохраняем регистр, так как он будет затёрт subi r17,-0x30; Десятки преобразуем в ASCII mov r16,r17;Копируем в R16 rcall LCD_WriteData;И выводим на дисплей pop r16; Достаём R16 subi r16,-0x30; Единицы преобразуем в ASCII rcall LCD_WriteData;И выводим на дисплей ;Конец ret
Программа использует модули HD44780.asm – библиотека для работы с дисплеем, sofi-iic.asm – библиотека для программной реализации I2C, DS1307.asm – библиотека для DS1307.
I2C реализован программно из-за плохой переносимости кода для работы с аппаратным TWI модулем на разные AVR’ки.
Крнфигурация.
Библиотека для работы с I2C для настройки имеет в начале следующие определения:
.equ SCL = PC5;Пин, который будет являться SCL .equ SDA = PC4;Пин, который будет являться SDA .equ IIC_PORT = PORTC;Порт, на котором будет I2C .equ IIC_DDR = DDRC; DDR, на котором будет I2C .equ IIC_PIN = PINC; Пин, на котором будет I2C
Собственно, из комментариев, я думаю, всё понятно.
Библиотека для работы с DS1307 в настройке не нуждается, но для работы требует либу для I2C.
Библиотека имеет следующие подпрограммы:
RTC_Start - запуск хода часов. Запускам в области инициализации программы. Никаких параметров нет. RTC_Stop - осановка часов. RTC_Get_Time - чтение времени. После выполнения в соответствующих переменных в оперативной памяти(о них ниже) появляются значения RTC_Get_Date - чтение даты. То-же самое, только для даты. RTC_Set_Time - установка времени. Перед установкой записываем в соответствующие переменные нужные значения и часы настраиваются. RTC_Set_Date - установка даты.
А вот переменные, про которые я говорил:
.dseg ;Переменные в оперативной памяти Hours: .byte 1; 1 байт под часы Minutes: .byte 1; 1 байт под минуты Days: .byte 1; 1 байт под дни Month: .byte 1; 1 байт под месяц Weekday: .byte 1; 1 байт для дня недели Year: .byte 2; Год в 1 байт не помещается, поэтому 2
Их нужно объявить самостоятельно в начале программы, в сегменте оперативки(dseg). Запись производится при помощи следующих команд:
sts hours,r16;Запись в переменную. Значение предварительно заносим в R16 lds r16,hours;Чтение из переменной. Результат будет в R16
Остальное, я думаю, понятно. Исходник, а также и библиотеки, хорошо прокомментированы, поэтому разобраться будет не сложно.
Скачать проект sClock + модель в Proteus
Все вопросы задаем на форуме
radioelektr.ru