Программирование микроконтроллеров. Часть 12-2
Делаем простейшие часы
Как видите, LCD индикатор подключен в 4-битном режиме. В одном из прошлых уроков я уже показывал, как подключить LCD индикатор к микроконтроллеру. Поэтому часть кода, который отвечает за инициализацию индикатора я взял из прошлого урока. Код файла lcd.c:
#include "main.h"
void send_half_byte(unsigned char c)
{
c<<=4;
e1; //включаем линию Е
_delay_us(50);
PORTD&=0b00001111; //стираем информацию на входах DB4-DB7, остальное не трогаем
PORTD|=c;
e0; //выключаем линию Е
_delay_us(50);
}
void send_byte(unsigned char c, unsigned char mode)
{
if (mode==0) rs0;
else rs1;
unsigned char hc=0;
hc=c>>4;
send_half_byte(hc); send_half_byte(c);
}
void send_char_lcd(unsigned char c)
{
send_byte(c,1);
}
void set_pos(unsigned char x, unsigned y)
{
char adress;
adress=(0x40*y+x)|0b10000000;
send_byte(adress, 0);
}
void LCD_ini(void)
{
_delay_ms(15); //Ждем 15 мс (стр 45)
send_half_byte(0b00000011);
_delay_ms(4);
send_half_byte(0b00000011);
_delay_us(100);
send_half_byte(0b00000011);
_delay_ms(1);
send_half_byte(0b00000010);
_delay_ms(1);
send_byte(0b00101000, 0); //4бит-режим (DL=0) и 2 линии (N=1)
_delay_ms(1);
send_byte(0b00001100, 0); //включаем изображение на дисплее (D=1), курсоры никакие не включаем (C=0, B=0)
_delay_ms(1);
send_byte(0b00000110, 0); //курсор (хоть он у нас и невидимый) будет двигаться влево
_delay_ms(1);
}
void clear_lcd(void)
{
send_byte(0b00000001, 0);
_delay_us(1500);
}
void str_lcd (char str1[])
{
wchar_t n;
for(n=0;str1[n]!='\0';n++)
send_char_lcd(str1[n]);
}
В главный заголовочный файл main.ini я добавил следующие строки:
#ifndef MAIN_H_
#define MAIN_H_
#define F_CPU 8000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <stdio.h>
#include <stdlib.h>
void LCD_ini(void);
void set_pos(unsigned char x, unsigned y);
void str_lcd (char str1[]);
void clear_lcd(void);
void send_char_lcd(unsigned char c);
#define e1 PORTD|=0b00001000 // установка линии E в 1
#define e0 PORTD&=0b11110111 // установка линии E в 0
#define rs1 PORTD|=0b00000100 // установка линии RS в 1 (данные)
#define rs0 PORTD&=0b11111011 // установка линии RS в 0 (команда)
void I2C_Init (void); //инициализация i2c
void I2C_Start_Condition(void); //Отправим условие START
void I2C_Stop_Condition(void); //Отправим условие STOP
void I2C_Send_Byte(unsigned char c); //передача байта в шину
void I2C_Send_Byte_By_ADDR(unsigned char c,unsigned char addr); //передача байта в шину на устройство по адресу
unsigned char I2C_Read_Byte(void); //читаем байт
unsigned char I2C_Read_Last_Byte(void); //читаем последний байт
unsigned char RTC_Convert_From_Dec(unsigned char c); //перевод двоично-десятичного числа в десятичное
unsigned char RTC_Convert_From_Bin_Dec(unsigned char c); //перевод десятичного числа в двоично-десятичное
#endif /* MAIN_H_ */
Необходимо в файле main.ini задать глобальные переменные для хранения показаний времени, даты и дня недели unsigned char sec,min,hour,day,date,month,year;
Добавим к нашему проекту еще один файл – RTC.c:
#include "main.h"
//преобразование двоично-десятичного числа в десятичное
unsigned char RTC_Convert_From_Dec(unsigned char c)
{
unsigned char ch = ((c>>4)*10+(0b00001111&c));
return ch;
}
//преобразование десятичного числа в двоично-десятичное
unsigned char RTC_Convert_From_Bin_Dec(unsigned char c)
{
unsigned char ch = ((c/10)<<4)|(c%10);
return ch;
}
Здесь будет проходить преобразование двоично-десятичного числа в десятичное и наоборот.
Добавим к проекту еще один файл twi.c в котором будет проходить обмен данными микроконтроллера с микросхемой DS1307 по протоколу I2C:
#include "main.h"
void I2C_Init (void)
{
TWBR=0x20;//скорость передачи (при 8 мгц получается 100 кгц, что и необходимо для общения с ds1307)
}
void I2C_Start_Condition(void)
{
TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
while (!(TWCR & (1<<TWINT)));//подождем пока установится TWIN
}
void I2C_Stop_Condition(void)
{
TWCR = (1<<TWINT)|(1<<TWSTO)|(1<<TWEN);
}
void I2C_Send_Byte(unsigned char c)
{
TWDR = c;//запишем байт в регистр данных
TWCR = (1<<TWINT)|(1<<TWEN);//включим передачу байта
while (!(TWCR & (1<<TWINT)));//подождем пока установится TWIN
}
void I2C_Send_Byte_By_ADDR(unsigned char c,unsigned char addr)
{
I2C_Start_Condition(); // Отправим условие START
I2C_Send_Byte(addr); // Отправим в шину адрес устройства + бит чтения-записи
I2C_Send_Byte(c);// Отправим байт данных
I2C_Stop_Condition();// Отправим условие STOP
}
unsigned char I2C_Read_Byte(void)
{
TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWEA);
while (!(TWCR & (1<<TWINT)));//ожидание установки бита TWIN
return TWDR;//читаем регистр данных
}
unsigned char I2C_Read_Last_Byte(void)
{
TWCR = (1<<TWINT)|(1<<TWEN);
while (!(TWCR & (1<<TWINT)));//ожидание установки бита TWIN
return TWDR;//читаем регистр данных
}
В теле цикла while
файла main.c напишем следующие строки:
//Читаем данные
I2C_Send_Byte_By_ADDR(0,0b11010000); //переходим на адрес 0
_delay_ms(300);
I2C_Start_Condition(); //Отправим условие START
I2C_Send_Byte(0b11010001); //отправим в устройство бит чтения
sec = I2C_Read_Byte();
min = I2C_Read_Byte();
hour = I2C_Read_Byte();
day = I2C_Read_Byte();
date = I2C_Read_Byte();
month = I2C_Read_Byte();
year = I2C_Read_Last_Byte();
I2C_Stop_Condition(); //Отправим условие STOP
sec = RTC_Convert_From_Dec(sec); //Преобразуем в десятичный формат
min = RTC_Convert_From_Dec(min); //Преобразуем в десятичный формат
hour = RTC_Convert_From_Dec(hour); //Преобразуем в десятичный формат
day = RTC_Convert_From_Dec(day); //Преобразуем в десятичный формат
year = RTC_Convert_From_Dec(year); //Преобразуем в десятичный формат
month = RTC_Convert_From_Dec(month); //Преобразуем в десятичный формат
date = RTC_Convert_From_Dec(date); //Преобразуем в десятичный формат
set_pos(3,0); //Устанавливаем позицию курсора
В этом коде происходит чтение данных с микросхемы DS1307. Ниже напишем код выводящий данные на дисплей:
//выводим данные на дисплей
send_char_lcd(date/10+0x30);//Преобразуем число в код числа
send_char_lcd(date%10+0x30);//Преобразуем число в код числа
send_char_lcd('.');
send_char_lcd(month/10+0x30);//Преобразуем число в код числа
send_char_lcd(month%10+0x30);//Преобразуем число в код числа
send_char_lcd('.');
send_char_lcd('2');
send_char_lcd('0');
send_char_lcd(year/10+0x30);//Преобразуем число в код числа
send_char_lcd(year%10+0x30);//Преобразуем число в код числа
set_pos(4,1); //Устанавливаем позицию курсора
send_char_lcd(hour/10+0x30);//Преобразуем число в код числа
send_char_lcd(hour%10+0x30);//Преобразуем число в код числа
send_char_lcd(':');
send_char_lcd(min/10+0x30);//Преобразуем число в код числа
send_char_lcd(min%10+0x30);//Преобразуем число в код числа
send_char_lcd(':');
send_char_lcd(sec/10+0x30);//Преобразуем число в код числа
send_char_lcd(sec%10+0x30);//Преобразуем число в код числа
Наши часы готовы. Можно скомпилировать код и проверить его работу в программе Proteus:
Если есть вопросы и предложения по этому уроку, пишите комментарии буду рад ответить на ваши вопросы.
Часть 1 Часть 2-1 Часть 2-2 Часть 3-1 Часть 3-2 Часть 4-1 Часть 4-2 Часть 5 Часть 6-1 Часть 6-2 Часть 7 Часть 8-1 Часть 8-2 Часть 9 Часть 10 Часть 11-1 Часть 11-2 Часть 12-1