Попалась мне плата готовая с четырьмя семисегментными индикаторами, семисегментным дешифратором и четыримя ключевыми транзисторами.
В динамическом режиме (режим поочерёдной быстрой развёртки) на семисегментных индикаторах можно получать разные цифры, даже с одним дешифратором. Задумал подключить её к моей плате с регистрами, про которую я публиковал "статью" в предыдущей теме, и попробывать написать программку для индикации системного времени (в формате "ЧЧММ") на данных индикаторах. Там также присутствует 8-й сегмент - децимальная точка, которая по моей идее будет служить для визуализации секунд. В динамическом режиме, как я увидел, индикаторы горят в половину своей яркости, ибо не успевает полностью зажечься, как он тушиться и зажигается соседний. Из 16 портов регистра (у меня два по 8) я задействовал 9 портов: 4 порта для посыла бинарного кода отображаемой цифры на дешифратор, 4 порта на 4 ключа 4-х индикаторов и один порт на децимальную точку для визуализации секунд. Если обойтись без последнего, достаточно будет 8-ми портов, а следовательно, одного 8-портового регистра.
#include <stdio.h>
#include <iostream>
#include <windows.h>
#include "conio.h"
#include <fstream>
#include <stdlib.h>
using namespace std;
void DTR1(HANDLE h){
EscapeCommFunction(h,
6);
}
void DTR0(HANDLE h){
EscapeCommFunction(h,
5);
}
void RTS1(HANDLE h){
EscapeCommFunction(h,
4);
}
void RTS0(HANDLE h){
EscapeCommFunction(h,
3);
}
void TX1(HANDLE h){
EscapeCommFunction(h,
8);
}
void TX0(HANDLE h){
EscapeCommFunction(h,
9);
}
//Функция, возводящая целочисленное число в целочисленную степень.
Стандартная функция pow работает некорректно.
int pow1(int a,int b){
int i,c;
c=1;
for(i=0;i<b;i++){
c*=a;
}
return c;
}
int main(){
HANDLE h;
h =
CreateFile("COM1",
GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if(h==INVALID_HANDLE_VALUE){
printf("COM1 port open error\n");
scanf("1");
}
int i,j,t,m;
int a[4]; //Массив цифр, отображаемые на индикаторах.
SYSTEMTIME st; //Структурная
переменная, в которую будут записаны текущие данные системмного времени,
начиная от года и заканчивая милисекундами.
while(1){ //Бесконечный цикл для непрерывного быстрого сканирования
индикаторов.
GetLocalTime(&st); //Получить текущее состояние системного времени и записать
в переменную st.
m=st.wHour; //Записать
в переменную m часы из st.
//Цикл,
"вытаскивающий" цифры из двухзначного числа m (часы) одним из
многочисленных способов. Если число меньше 10, ноль слева припишется
автоматически. Две цифры (десятки и еденицы часов) запишутся в 1 и 2 элементы
массива a[] и в дальнейшем будут отображены на 1 и 2 индикаторах.
for(i=0;i<=1;i++){
a[i]=0;
while(m>=pow1(10,1-i)){
m-=pow1(10,1-i);
a[i]+=1;
}
}
m=st.wMinute; //Записать
в переменную m минуты из st.
//Цикл,
аналогичный циклу выше, только для минут. Две цифры (десятки и еденицы минут)
запишутся в 3 и 4 элементы массива a[] и в дальнейшем будут отображены на 3 и 4
индикаторах.
for(i=0;i<=1;i++){
a[i+2]=0;
while(m>=pow1(10,1-i)){
m-=pow1(10,1-i);
a[i+2]+=1;
}
}
m=st.wSecond; //Записать
в переменную m секунды из st.
//Цикл по
чередованию индикаторов (динамический режим).
for(i=0;i<4;i++){
//Запись
1-ого бита в регистр, соответствующий состоянию соединённых в месте выводов
"dp" (сегмент h, децимальная точка) семисегментных индикаторов.
Программа предполагает ежесекундное переключение этой точки с индикатора на
следующий за ним индикатор. Таким образом эмулируется "тик" часов.
Нижепреведённое условие обеспечивает посыл логической "1" в случае,
если совпадает текущий номер четверти четвёрок секунд с текущим номером
индикатора (i).
if(m-m/4*4==i){
//Вычисление остатка в результате деления значения
секунд на 4. Это и будет вышеописанный номер четверти.
RTS0(h);
}else{
RTS1(h);
}
//Запись
1-ого бита в регистр.
DTR1(h);
DTR0(h);
t=a[i]; //Запись
во временную переменную t значение i-ой цифры, соответствующий текущему
индикатору.
//Цикл,
в котором десятичное число (вышеуказанная цифра) осуществляется преобразование
в двоичное и биты этого числа сразу же записываются в регистр.
for(j=0;j<4;j++){
//Даже если будет достаточно представить число t
тремя или меньше битами, двоичное число будет дополнено нулями до 4-х бит.
if(t-t/2*2){
//Расчёт остатка в результате деления на 2. Это будет
текущий j-ый бит.
RTS0(h);
}else{
RTS1(h);
}
//Запись
этого бита в регистр.
DTR1(h);
DTR0(h);
t=t/2; //Целочисленное
деление на 2 для дальнейшего повтора операции разложения на биты в цикле.
}
//Следующий
цикл определяет номера дисплеев, которые зажгуться в зависимости от текущего i.
Нам нужно, чтобы загорался один i-ый дисплей, а все остальные были блокированы.
for(j=0;j<4;j++){
if(j==i){
//Передача логической "1" в случае
вышеуказанного совпадения. Во всех остальных трёх случаях - "0".
RTS0(h);
}else{
RTS1(h);
}
//Запись
последних 4-х битов в регистр.
DTR1(h);
DTR0(h);
}
//В
регистр записаны все 9 битов. Нижеуказанными функциями осуществляется открытие
регистра на мгновение.
TX1(h);
TX0(h);
}
}
scanf("1");
TX0(h);
RTS1(h);
for(i=0;i<16;i++){
DTR1(h);
DTR0(h);
}
TX1(h);
CloseHandle(h);
return 0;
}
|