Спасибо! Программу сделал. Код получился следующий:
Код
#include <p18f6722.h>
#include <stdio.h>
#pragma config OSC = XT // Применяю внешний кварцевый резонатор
#pragma config WDT = OFF // Внутренний сторожевой таймер отключаю - применяется внешний, который нужно периодически обнулять сигналом ADR0
#define ADDR_HL1 0x3 // определяю адрес первого индикатора HL1 0x03, как переменную ADDR_HL1
#define ADDR_HL2 0x4 // определяю адрес второго индикатора HL2 0x04, как переменную ADDR_HL2
#define ADDR_HL3 0x5 // определяю адрес третьего индикатора HL3 0x05, как переменную ADDR_HL3
#define ADDR_HL4 0x6 // определяю адрес четвертого индикатора HL4 0x06, как переменную ADDR_HL4
#define ADDR_HL5 0x7 // определяю адрес пятого индикатора HL5 0x07, как переменную ADDR_HL5
#define ADDR_HL6 0x8 // определяю адрес шестого индикатора HL6 0x08, как переменную ADDR_HL6
#define ADDR_HL7 0x9 // определяю адрес седьмого индикатора HL7 0x09, как переменную ADDR_HL7
#define ADDR_HL8 0xA // определяю адрес восьмого индикатора HL8 0x0A, как переменную ADDR_HL8
#define LED_CODE_0 0xC0 //определяю переменную, при которой на индикаторе будет отображаться "0"
#define LED_CODE_1 0xF9 //определяю переменную, при которой на индикаторе будет отображаться "1"
#define LED_CODE_2 0xA4 //определяю переменную, при которой на индикаторе будет отображаться "2"
#define LED_CODE_3 0xB0 //определяю переменную, при которой на индикаторе будет отображаться "3"
#define LED_CODE_4 0x99 //определяю переменную, при которой на индикаторе будет отображаться "4"
#define LED_CODE_5 0x92 //определяю переменную, при которой на индикаторе будет отображаться "5"
#define LED_CODE_6 0x82 //определяю переменную, при которой на индикаторе будет отображаться "6"
#define LED_CODE_7 0xF8 //определяю переменную, при которой на индикаторе будет отображаться "7"
#define LED_CODE_8 0x80 //определяю переменную, при которой на индикаторе будет отображаться "8"
#define LED_CODE_9 0x90 //определяю переменную, при которой на индикаторе будет отображаться "9"
#define LED_CODE_E 0x86 //определяю переменную, при которой на индикаторе будет отображаться "E"
#define LEDCODE_X 0xFF //определяю переменную, при которой на индикаторе не будет отображаться ни один сегмент
#define PORT_DATA PORTD //определяю PORTD, как переменную PORT_DATA
#define PORT_ADDR PORTE //определяю PORTE, как переменную PORT_ADDR
void Indicator(char addrCode, char dataCode); //определяю функцию с именем Indicator, char - символьный тип данных
void Indicator(char addrCode, char dataCode) //ввожу параметры функции, т.е. значения, которые будут находиться под именам addrCode и dataCode.
{
PORT_ADDR = addrCode; //под параметром addrCode будет значение переменной PORT_ADDR
PORT_DATA = dataCode; //под параметром dataCode будет значение переменной PORT_DATA
}
char i; //переменная i - счетчик перебора индикаторов в основной программе
char out[7];
int UREFmv, ADCcode, Umv; //переменная "UREFmv"-величина опорного напряжения
char NADC, KATT; //переменная "NADC"-разрядность АЦП (у PIC18F6722 - 10 bit); переменная "KATT"-коээфициент делителя (ослабления аттенюатора) на входе
float volts; //переменная "volts" - с плавающей запятой
char buf[5+1]; //организую первый буфер для результата с АЦПр: максимальная отображаемая величина требует 5 знакомест + символ конца строки 0х00 в конце
char buf2[2+1+3+1]; //организую второй буфер: 2 на целую часть, 1 на точку, 3 - на друбную часть, 1 - на завершающий строку символ
const char IND_ADDR[]={0,ADDR_HL1,ADDR_HL1,ADDR_HL2,ADDR_HL3,ADDR_HL4}; //организую массив, каждый элемент которого - адрес индикатора, нулевой элемент массива не используется, const - размещаю в флеш-памяти МК
#pragma code //произвожу запись дальнейших данных в память программ
int IzmerVoltage (void) //организую подпрограмму запуска АЦП с результатом с плавающей запятой
{
ADCON0bits.GO=1; //запускаю преобразователь АЦП, записав 1 в бит1 регистра ADCON0
while (ADCON0bits.GO==1); //запускается цикл проверки работы АЦП. Окончание преобразование - окончание цикла
return ADRES*4.89;
}
void main (void) //точка входа в основную програму
{
ADCON0=0x15; //разрешаю работу АЦП (бит0=1), выбираю входа AN5 (биты2-5=0101)
ADCON1=0x09; //AN5-аналоговый вход (биты0-3=1001), AVDD и AVSS - опорные (биты4-5=00)
ADCON2=0x8C; //частота работы АЦП=1,5Мгц (биты0-2=100), время 2*Tad (биты3-5=001), результат АЦП justifield справа(бит7=1)
TRISD=0; //порт D - выход
TRISE=0; //порт E - выход
TRISF=1; //порт F - вход
Indicator(ADDR_HL1,LEDCODE_X); //сбрасываю индикатор HL1
Indicator(ADDR_HL2,LEDCODE_X); //сбрасываю индикатор HL2
Indicator(ADDR_HL3,LEDCODE_X); //сбрасываю индикатор HL3
Indicator(ADDR_HL4,LEDCODE_X); //сбрасываю индикатор HL4
Indicator(ADDR_HL5,LEDCODE_X); //сбрасываю индикатор HL5
Indicator(ADDR_HL6,LEDCODE_X); //сбрасываю индикатор HL6
Indicator(ADDR_HL7,LEDCODE_X); //сбрасываю индикатор HL7
Indicator(ADDR_HL8,LEDCODE_X); //сбрасываю индикатор HL8
while (1) //главный цикл
{
Umv=IzmerVoltage();
sprintf (buf, "%05d", Umv); //помещение значения с АЦП Umv в милливольтах в буфер buf, старшие незначащие цифры будут "0" (пример: "1234" - "01234")
buf2[0]=buf[0]; //в нулевой элемент буфера buf2 ввожу нулевой элемент буфера buf
buf2[1]=buf[1]; //в первый элемент буфера buf2 ввожу первый элемент буфера buf
buf2[2]='.'; //в второй элемент буфера buf2 ввожу точку "."
buf2[3]=buf[2]; //в третий элемент буфера buf2 ввожу второй элемент буфера buf
buf2[4]=buf[3]; //в четвертый элемент буфера buf2 ввожу третий элемент буфера buf
buf2[5]=buf[4]; //в пятый элемент буфера buf2 ввожу четвертый элемент буфера buf
buf2[6]='\0'; //в шестой элемент буфера buf2 ввожу символ конца строки 0х00
for (i=1;i<5;i=i+1) //организую цикл перебора шести индикаторов и заполнения их 6 элементами массива buf2 (кроме седьмого - нулевого)
{
switch (buf2[i]) //организую перебор содержимого буфера buf2 и сравнение с символами, которые нужно выводить на индикаторы
{
case '.':out[i]=out[i-1]+0x80; break; //если в массиве точка - вывожу в предыдущий индикатор точку и выход из цикла сравнения элемента, переход к следующему (break)
case '0':out[i]=LED_CODE_0; break; //если в массиве ноль - выводить на индикатор ноль и выход из цикла сравнения элемента, переход к следующему (break)
case '1':out[i]=LED_CODE_1; break; //если в массиве один - выводить на индикатор один и выход из цикла сравнения элемента, переход к следующему (break)
case '2':out[i]=LED_CODE_2; break; //если в массиве два - выводить на индикатор два и выход из цикла сравнения элемента, переход к следующему (break)
case '3':out[i]=LED_CODE_3; break; //если в массиве три - выводить на индикатор три и выход из цикла сравнения элемента, переход к следующему (break)
case '4':out[i]=LED_CODE_4; break; //если в массиве четыре - выводить на индикатор четыре и выход из цикла сравнения элемента, переход к следующему (break)
case '5':out[i]=LED_CODE_5; break; //если в массиве пять - выводить на индикатор пять и выход из цикла сравнения элемента, переход к следующему (break)
case '6':out[i]=LED_CODE_6; break; //если в массиве шесть - выводить на индикатор шесть и выход из цикла сравнения элемента, переход к следующему (break)
case '7':out[i]=LED_CODE_7; break; //если в массиве семь - выводить на индикатор семь и выход из цикла сравнения элемента, переход к следующему (break)
case '8':out[i]=LED_CODE_8; break; //если в массиве восемь - выводить на индикатор восемь и выход из цикла сравнения элемента, переход к следующему (break)
case '9':out[i]=LED_CODE_9; break; //если в массиве девять - выводить на индикатор девять и выход из цикла сравнения элемента, переход к следующему (break)
default: out[i]=LED_CODE_E; break; //в противном случае - высвечивать индикацию ошибки "Е" и переход к следующему элементу (break)
} //окончание перебора содержимого буфера buf2
Indicator(IND_ADDR[i],out[i]); //вывести полученное значение на необходимый индикатор
}; //конец цикла перебора
}
}
Теперь пробую написать программу, связанную с вводом цифр с клавиатуры 3х6 на семисегментный индикатор и выполнением простейших арифметических операций – сложение, вычитание, умножение и деление. Использоваться будут 4 индикатора. Также хочеться сделать ввод дробных чисел, т.е. ставить точку.
Сначала хотелось бы просто реализовать ввод чисел с клавиатуры и отображением их на экране (без точки). Контакты на клавиатуре – нормально открытые.
Матрица получилась следующая:
Нажмите для просмотра прикрепленного файлаНа столбцы сигналы подаются через дешифратор D4. На дешифратор подаются сигналы А0, А1, А2 с выходов PORTA – RA0, RA1, RA2 (ножки 24, 23, 22). Сигналы с строк считываются через сигналы INT0, INT1, INT2, которые подаются на входа PORTB – RB0, RB1, RB2 (ножки 48, 47, 46).
Текст программы пока вот такой:
Код
#include <p18f6722.h>
#pragma config OSC = XT // Применяю внешний кварцевый резонатор
#pragma config WDT = OFF // Внутренний сторожевой таймер отключаю - применяется внешний, который нужно периодически обнулять сигналом ADR0
#pragma config MCLRE = OFF // отключаю RESEЕ, данный вывод используется, как RG5
#define ADDR_HL1 0x3 // определяю адрес первого индикатора HL1 0x03, как переменную ADDR_HL1
#define ADDR_HL2 0x4 // определяю адрес второго индикатора HL2 0x04, как переменную ADDR_HL2
#define ADDR_HL3 0x5 // определяю адрес третьего индикатора HL3 0x05, как переменную ADDR_HL3
#define ADDR_HL4 0x6 // определяю адрес четвертого индикатора HL4 0x06, как переменную ADDR_HL4
#define ADDR_HL5 0x7 // определяю адрес пятого индикатора HL5 0x07, как переменную ADDR_HL5
#define ADDR_HL6 0x8 // определяю адрес шестого индикатора HL6 0x08, как переменную ADDR_HL6
#define ADDR_HL7 0x9 // определяю адрес седьмого индикатора HL7 0x09, как переменную ADDR_HL7
#define ADDR_HL8 0xA // определяю адрес восьмого индикатора HL8 0x0A, как переменную ADDR_HL8
#define LED_CODE_0 0xC0 //определяю переменную, при которой на индикаторе будет отображаться "0"
#define LED_CODE_1 0xF9 //определяю переменную, при которой на индикаторе будет отображаться "1"
#define LED_CODE_2 0xA4 //определяю переменную, при которой на индикаторе будет отображаться "2"
#define LED_CODE_3 0xB0 //определяю переменную, при которой на индикаторе будет отображаться "3"
#define LED_CODE_4 0x99 //определяю переменную, при которой на индикаторе будет отображаться "4"
#define LED_CODE_5 0x92 //определяю переменную, при которой на индикаторе будет отображаться "5"
#define LED_CODE_6 0x82 //определяю переменную, при которой на индикаторе будет отображаться "6"
#define LED_CODE_7 0xF8 //определяю переменную, при которой на индикаторе будет отображаться "7"
#define LED_CODE_8 0x80 //определяю переменную, при которой на индикаторе будет отображаться "8"
#define LED_CODE_9 0x90 //определяю переменную, при которой на индикаторе будет отображаться "9"
#define LED_CODE_X 0xFF //определяю переменную, при которой на индикаторе не будет отображаться ни один сегмент
#define PORT_DATA LATD //определяю LATD, как переменную PORT_DATA
#define PORT_ADDR LATE //определяю LATE, как переменную PORT_ADDR
#define NUMBER_COLOWN LATA //определяю LATA, как переменную NUMBER_COLOWN
#define NUMBER_ROW LATB //определяю LATB, как переменную NUMBER_ROW
void Indicator(char addrCode, char dataCode); //определяю функцию с именем Indicator, char - символьный тип данных
void Indicator(char addrCode, char dataCode) //ввожу параметры функции, т.е. значения, которые будут находиться под именам addrCode и dataCode.
{
PORT_ADDR = addrCode; //под параметром addrCode будет значение переменной PORT_ADDR
PORT_DATA = dataCode; //под параметром dataCode будет значение переменной PORT_DATA
}
char out, i;
char SIMVOL;
char buf[4+1]; //первый буфер для ввода чисел: 4 знака + символ конца строки 0х00 в конце
const int IND_ADDR[]={0,ADDR_HL4,ADDR_HL3,ADDR_HL2,ADDR_HL1}; //массив, элементы-индикаторы, нулевой элемент-не используется
void delay (void) //организую подпрограмму задержки
{
unsigned int i;
for (i==0; i<10000; i++); //длительность задержки опрделяется величиной i
}
int Nomer_klavishi (void) //Определение символа нажатой клавиши
{
TRISA=0xF8; //порт A - выход
TRISB=0xFF; //порт В - вход
ADCON1=0xF; //отключаю АЦП, все выводы - цифровые
SIMVOL=0; //значение переменной при отсутствии нажатии клавиши
NUMBER_COLOWN=0x00; //выдаю 0 на столбец 1
if (PORTBbits.RB0==0) SIMVOL=1; //проверяю 0 на строке 1
else if (PORTBbits.RB1==0) SIMVOL=2; //проверяю 0 на строке 2
else if (PORTBbits.RB2==0) SIMVOL=3; //проверяю 0 на строке 3
NUMBER_COLOWN=0x01; //выдаю 0 на столбец 2
if (PORTBbits.RB0==0) SIMVOL=4; //проверяю 0 на строке 1
else if (PORTBbits.RB1==0) SIMVOL=5; //проверяю 0 на строке 2
else if (PORTBbits.RB2==0) SIMVOL=6; //проверяю 0 на строке 3
NUMBER_COLOWN=0x02; //выдаю 0 на столбец 3
if (PORTBbits.RB0==0) SIMVOL=7; //проверяю 0 на строке 1
else if (PORTBbits.RB1==0) SIMVOL=8; //проверяю 0 на строке 2
else if (PORTBbits.RB2==0) SIMVOL=9; //проверяю 0 на строке 3
NUMBER_COLOWN=0x03; //выдаю 0 на столбец 4
if (PORTBbits.RB0==0) SIMVOL=10; //проверяю 0 на строке 1
else if (PORTBbits.RB1==0) SIMVOL=11; //проверяю 0 на строке 2
else if (PORTBbits.RB2==0) SIMVOL=12; //проверяю 0 на строке 3
NUMBER_COLOWN=0x04; //выдаю 0 на столбец 5
if (PORTBbits.RB0==0) SIMVOL=13; //проверяю 0 на строке 1
else if (PORTBbits.RB1==0) SIMVOL=14; //проверяю 0 на строке 2
else if (PORTBbits.RB2==0) SIMVOL=15; //проверяю 0 на строке 3
NUMBER_COLOWN=0x05; //выдаю 0 на столбец 6
if (PORTBbits.RB0==0) SIMVOL=16; //проверяю 0 на строке 1
else if (PORTBbits.RB1==0) SIMVOL=17; //проверяю 0 на строке 2
else if (PORTBbits.RB2==0) SIMVOL=18; //проверяю 0 на строке 3
return (SIMVOL);
}
void main (void) //точка входа в основную програму
{
TRISD=0; //порт D - выход
TRISE=0; //порт E - выход
Indicator(ADDR_HL1,LED_CODE_X); //сбрасываю индикатор HL1
Indicator(ADDR_HL2,LED_CODE_X); //сбрасываю индикатор HL2
Indicator(ADDR_HL3,LED_CODE_X); //сбрасываю индикатор HL3
Indicator(ADDR_HL4,LED_CODE_X); //сбрасываю индикатор HL4
Indicator(ADDR_HL5,LED_CODE_X); //сбрасываю индикатор HL5
Indicator(ADDR_HL6,LED_CODE_X); //сбрасываю индикатор HL6
Indicator(ADDR_HL7,LED_CODE_X); //сбрасываю индикатор HL7
Indicator(ADDR_HL8,LED_CODE_X); //сбрасываю индикатор HL8
i=1; //номер индикатора, в который будет вводиться символ с клавиатуры
out=LED_CODE_X; //пустое значение
while (1) //главный цикл
{
SIMVOL=Nomer_klavishi();
if (SIMVOL!=0)
Indicator(IND_ADDR[i+1],out); //вывожу ранее полученное значение на следующий индикатор, если раньше не вводилось, то ввожу пустоту
if (SIMVOL!=0) switch (SIMVOL) //начинаю цикл перебора символа для вывода на экран
{
case 1:out=LED_CODE_7; break; //загорается семь
case 2:out=LED_CODE_4; break; //загорается четыре
case 3:out=LED_CODE_1; break; //загорается один
case 4:out=LED_CODE_8; break; //загорается восемь
case 5:out=LED_CODE_5; break; //загорается пять
case 6:out=LED_CODE_2; break; //загорается два
case 7:out=LED_CODE_9; break; //загорается девять
case 8:out=LED_CODE_6; break; //загорается шесть
case 9:out=LED_CODE_0; break; //загорается ноль
case 12:out=LED_CODE_3; break; //загорается три
default:out=LED_CODE_X; break; //ничего не загорается
};
if (SIMVOL!=0) Indicator(IND_ADDR[i],out); //вывожу полученное значение на индикатор
if (SIMVOL!=0) i=i+1; //если ранее был введен символ с клавиатуры, то следующий вводиться в следующий индикатор
delay (); //пауза
}
}
При вводе цифр с клавиатуры текст вводиться, но ввод осуществляется справа на лево, т.е. сначала цифра вводиться в HL4, HL3, HL2 и затем в HL1. Хочется реализовать ввод, как в обычном калькуляторе, т.е. число вводиться в правый сегмент, а все введенные ранее элементы синхронно сдвигаются влево. Слышал, что есть операция memcpy и ею можно реализовать сдвиг, слышал про то, что можно использовать тип переменной long int и организовать побайтный сдвиг влево. Думаю, что можно осуществить это же ввод на цикле условия «if», но будет очень большой текст этого участка программы. Какой способ лучше выбрать?