Уважаемые пользователи Голос!
Сайт доступен в режиме «чтение» до сентября 2020 года. Операции с токенами Golos, Cyber можно проводить, используя альтернативные клиенты или через эксплорер Cyberway. Подробности здесь: https://golos.io/@goloscore/operacii-s-tokenami-golos-cyber-1594822432061
С уважением, команда “Голос”
GOLOS
RU
EN
UA
evgenij-byvshev
7 лет назад

Программирование микроконтроллеров. Часть 12-2

Делаем простейшие часы

В прошлом уроке я рассказал про микросхему реального времени DS1307. Сегодня я покажу как её можно подключить к микроконтроллеру и собрать простейшие часы. На этот раз я решил использовать микроконтроллер ATMEGA8. Для этого в программе Proteus я нарисовал следующую схему:

Как видите, 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

49
290.501 GOLOS
На Golos с February 2017
Комментарии (1)
Сортировать по:
Сначала старые