По просьбе одного из комментаторов моего блога решил выложить вот такой простой пример. Микроконтроллер – 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
Toutes les questions à se poser forum
radioelektr.ru