Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Kharakhnin / Методичка_проектирование МП систем.doc
Скачиваний:
116
Добавлен:
08.03.2016
Размер:
1.92 Mб
Скачать

5.2. Описание функций для работы с sdk 1.1

В программе для СДК мы будем использовать готовые функции, написанные на языке С, для работы с различными компонентами СДК. Также нам понадобятся два файла с набором констант.

  1. Файл ADUC812.h содержит адреса всех регистров микроконтроллера. Этот файл находится в папке Keil/C51/INC/ADI.

  2. Файл ser_inc.h содержит набор констант и команд. Вот его содержимое:

#define TRUE 1 //логическая 1

#define FALSE 0//логический 0

#define MAXBASE 0x08//8-ая страница памяти

#define RAM_TABLE 0x2000//базовый адрес пользовательской таблицы векторов прерываний

#define LJMP 0x2//код команды LJMP

// Регистры PLIS MAX

#define KB 0x0000//регистр клавиатуры

#define EXT_LO 0x0002//

#define EXT_HI 0x0003//

#define ENA 0x0004//регистр звука

#define SV 0x0007//р.светодиодов

#define DATA_IND 0x0001//р.данных ЖКИ

#define C_IND 0x0006//р.команд ЖКИ

//---

// Константы для LCD

//--Команды для контроллера LCD

#define CLEAR 0x01 //requires delay cylce of min 57 NOPs

#define HOME 0x02

#define ENTRY_MODE 0x04

#define DISPLAY_CTRL 0x08

#define SHIFT 0x10

#define FUNCTION_SET 0x20

#define RAM_CG 0x40

#define RAM_DD 0x80

#define BF_AC 0x80 //Read Busy flag (DB7) and AC (DB6-0)

//--Опции для этих команд

#define INCR 0x02

#define DISPLAY_SHIFT 0x01

#define DISPLAY_ON 0x04

#define CURSOR_ON 0x02

#define BLINK 0x01

#define DISPLAY 0x08

#define RIGHT 0x04

#define EIGHT_BITS 0x10

#define TWO_LINE 0x08

//--

// Константы COM-порта

#define BUFFERLEN 16//размер буфера

#define S9600 0xFD//скорость передачи данных

#define S4800 0xFA

#define S2400 0xF4

#define S1200 0xE8

//--

// Константы для ЦАП и АЦП

#define VDD 5.0

#define BUSY 0x80 //АЦП производит преобразование

#define DAC0 0 // Каналы ЦАП

#define DAC1 1 //

#define ON 1

#define OFF 0

Функция записи в регистры ПЛИС

void WriteMax(unsigned char xdata *regnum, unsigned char val)

{

unsigned char oldDPP=DPP;//сохраняем текущую страницу памяти

DPP=MAXBASE;//переключаемся на 8-ую страницу памяти

*regnum=val;//заносим в регистр байт информации

DPP=oldDPP;//восстанавливаем значение страничного регистра

}

regnum – один из семи регистров ПЛИС.

val – число, которое нужно записать в regnum.

DPP – страничный регистр.

Функция чтения из регистров ПЛИС

unsigned char ReadMax(unsigned char xdata *regnum)

{

unsigned char oldDPP=DPP; //сохраняем текущую страницу памяти

unsigned char val=0;//обнуляем локальную переменную val

DPP=MAXBASE; //переключаемся на 8-ую страницу памяти

val=*regnum;// считываем байт из регистра ПЛИС

DPP=oldDPP; //восстанавливаем значение страничного регистра

return val;//возвращаем считанный байт в точку вызова данной функции

}

Функция инициализации СДК

void Initilization(void)

{

DACCON = 0x7F;//настройка ЦАП

ADCCON1 = 0xAC;// настройка АЦП

InitLCD();//инициализация ЖКИ

MyInitSIO();//инициализация СОМ-порта

SetVect(0x04,(void code*)COM_ISR);// установка вектора прерывания от СОМ-порта

IE=0x10;//разрешаем прерывания от СОМ-порта

EA=TRUE;//разрешаем окончательно

}

Функция воспроизведения звукового сигнала СДК

void Buzz(void)

{

int dur,i;//локальные переменные dur – длительность звучания

for(dur = 0; dur < 8000; dur++)//основной цикл

{

WriteMax(ENA,0x3C);//подаем ток на пьезоэлектрический элемент

for(i=0; i < 25; i++)continue;//задержка

WriteMax(ENA,0x20);//снимаем ток

for(i=0; i < 25; i++)continue;//задержка

}

}

Функция управления светодиодами СДК

void Svetik(bit tetrad)

{

int j,u;//переменные для циклов

if(tetrad)//если tetrad=1 то светодиоды будут загораться потетрадно

{

for(j=0;j<50;j++)//основной цикл

{

WriteMax(SV,0x0F);//зажигаем первые 4 светодиода

for(u=0;u<31000;u++) continue;//задержка

WriteMax(SV,0xF0);//зажигаем другие 4 светодиода

for(u=0;u<31000;u++) continue;//задержка

}

}else

{

WriteMax(SV,i);// зажигаем светодиоды

i++; i – инкремент глобальной переменной(определяет какие светодиоды горят)

}

}

Функция работы с клавиатурой СДК

При работе с клавиатурой СДК используются:

Массив KBTable, который содержит символы клавишСДК

char KBTable[]="147*2580369#ABCD";

Глобальная переменная symbol_from_kb, в ней находится символ нажатой клавишы после опроса клавиатуры.

char* symbol_from_kb;

bit ScanKBOnce(char *ch)//Опрос клавиатуры

{

unsigned char row,col,rownum,colnum;

unsigned int i;

for(colnum = 0; colnum < 4; colnum++)//цикл по столбцам

{

col = 0x1 << colnum; //Формируем 0001,0010,0100,1000,0001,...

WriteMax(KB,~col);//Заносим в регистр клавиатуры 11111110,11111101,11111011,11110111,11111110,...

for(rownum = 0; rownum < 4; rownum++)//цикл по строкам

{

row = ReadMax(KB) & (0x10 << rownum);//считываем из регистра клавиатуры

if( !row ) // если клавиша нажата

{

for(i = 0; i<10000; i++)continue;//задержка из-за дребезга контакта

row = ReadMax(KB) & (0x10 << rownum);// опять считываем из регистра клавиатуры

if( !row )// теперь клавиша точно нажата

{

*ch = (KBTable[(colnum<<2) + rownum]);//в ch символ нажатой клавиши.

return 1; // успешный выход из функции

}

}

}

}

return 0; // функция ScanKBOnce возвращает 0 если клавиша не нажата

}

Функции для работы с СОМ-портом СДК

void WSio(unsigned char Sym)//запись символа в порт

{

SBUF=Sym;//помещаем символ Sym в регистр SBUF

TI=0;// сбрасываем флаг TI

while(!TI);//ждем окончания передачи символа

TI=0;// сбрасываем флаг TI

}

unsigned char RSio(void)//чтение символа из порта

{

while(!RI);//ждем окончания приема символа

RI=0;//сбрасываем флаг RI

return SBUF;//возвращаем символ

}

void Type(char * Str)//запись строки в порт

{

while(*Str)//пока не дойдем до конца строки идет запись в порт

WSio(*Str++);//запись символа в порт и переход к следующему символу в строке

}

void MyInitSIO(void)//инициализация последовательного порта

{

T3CON= 0x83; //настройка таймера-счетчика2

T3FD= 0x2D;//

SCON= 0x50;//настройка СОМ-порта

}

Функции для работы с АЦП и ЦАП

void SetVoltage(float v, bit channel)//установка напряжения

{

unsigned short max_val;//максимальное значение

unsigned short val;//значение напряжения

if(DACCON & 0x80)// если 8-ми битый режим

{

max_val = 0xFF;//то максимальное значение=255

}

else // если 12-битный режим

{

max_val = 0xFFF;// то максимальное значение=4095

}

val = (unsigned short)(v * max_val / VDD); //преобразуем напряжение v к нужному виду

val &= max_val;

if(channel == DAC0)//если выбран канал 0 ЦАП

{

DAC0H = val >> 8; //заносим значение напряжения в регистры

DAC0L = val;

}

else//если выбран канал 1 ЦАП

{

DAC1H = val >> 8;// заносим значение напряжения в регистры

DAC1L = val;//

}

}

float GetVoltage(unsigned char channel)//получение напряжения

{

float v;//локальная переменная

while(ADCCON3 & BUSY);// ждем окончание преобразования, то есть когда бит BUSY=0

ADCCON2 = 0x10 | channel ;// выбираем канал channel

while(ADCCON3 & BUSY); // ждем окончание преобразования

v = ((unsigned short)(ADCDATAH&0xF) << 8) | ADCDATAL;//результат преобразования в переменную v

v = v * 5.0 / 0xFFF;//преобразуем v

return v;//возвращаем результат преобразования

}

Функции для работы с ЖКИ СДК

При работе с дисплеем СДК используются:

Глобальная переменная CurPosCtrl. С помощью нее можно контролировать позицию курсора.

static bit CurPosCtrl=1;

Глобальная переменная cur_x. Она определяет позицию курсора в строке дисплея.

static char cur_x=0;

Глобальная переменная cur_y. Она определяет одну из двух строк дисплея.

static char cur_y=0;

void SwitchCurPosControl(bit o)//активация или деактивация курсора

{

CurPosCtrl=o;

}

void Strobe(char c)//стробирование информации

{

unsigned int i;//локальная переменная

WriteMax(C_IND,c | 0x1);// установка строба

WriteMax(C_IND,c & 0xFE);//сброс строба

for (i=0;i<300;i++)continue;// задержка

}

void LCD_SwitchCursor(bit cursor, bit blink)//переключение курсора

{

unsigned char i=0;

WriteMax( DATA_IND, DISPLAY_CTRL |

DISPLAY_ON |

((cursor)?CURSOR_ON:0) |

((blink)?BLINK:0) );// код команды переключения в регистр данных ЖКИ

Strobe(0x8); //R/W = 0; RS = 0

}

void LCD_Clear(void)//очистка дисплея

{

int i;

WriteMax(DATA_IND, CLEAR);//код команды очистки в регистр данных ЖКИ

Strobe(0x8); //очистка

cur_x = 0;//курсор на первое знакоместо

cur_y = 0;//первой строки

// for(i=0; i<1600; i++)continue;

}

void InitLCD(void)//инициализация ЖКИ

{

unsigned short i;

for(i=0; i<4000; i++)continue;

// cmd = 0x30; //

WriteMax(DATA_IND, FUNCTION_SET|EIGHT_BITS);

Strobe(0x8);

for(i=0; i<1500; i++)continue;

// cmd = 0x30; //

WriteMax(DATA_IND, FUNCTION_SET|EIGHT_BITS);

Strobe(0x8);

for(i=0; i<50; i++)continue;

// cmd = 0x30; //

WriteMax(DATA_IND, FUNCTION_SET|EIGHT_BITS);

Strobe(0x8);

// for(i=0; i<100; i++)continue;

// cmd = 0x38; //

WriteMax(DATA_IND, FUNCTION_SET|EIGHT_BITS|TWO_LINE);

Strobe(0x8);

// cmd = 0x08; //

WriteMax(DATA_IND, DISPLAY_CTRL); //Display off

Strobe(0x8);

// cmd = 0x01; //

WriteMax(DATA_IND, CLEAR);

Strobe(0x8);

// for(i=0; i<1600; i++)continue;

WriteMax(DATA_IND, ENTRY_MODE|INCR);

Strobe(0x8);

// cmd = 0x0F; //Display ON

WriteMax(DATA_IND, DISPLAY_CTRL|DISPLAY_ON); //Cursor OFF, Blinking OFF

Strobe(0x8);

}

void LCD_Putch(char ch)//вывод символа на дисплей

{

if(CurPosCtrl)//если курсор разрешен

{

LCD_GotoXY(cur_x,cur_y);//перемещаем курсор

if(++cur_x>15)cur_x=0,cur_y=~cur_y;//если символ не влезает в строку, то переключаемся на первое знакоместо другой строки

}

WriteMax(DATA_IND,ch);//помещаем символ в регистр данных ЖКИ

Strobe(0xC); //R/W = 0, RS = 1 строб-сигнал

}

void LCD_GotoXY(unsigned char x,bit y)//перевод курсора на знакоместо y – строка дисплея, x – позиция в строке.

{

WriteMax(DATA_IND,RAM_DD|(x+((y)?0x40:0)));//переключаем курсор

Strobe(0x8); //стробируем

cur_x = x;//сохраняем текущее знакоместо

cur_y = y;//сохраняем текущую строку

}

void LCD_Type(char* s)//вывод строки на дисплей

{

bit t = CurPosCtrl;//сохраняем значение переменной CurPosCtrl

SwitchCurPosControl(1);//разрешаем курсор

while(*s)//пока не дойдем до конца строки

LCD_Putch(*s++);//выводим очередной символ и переходим к следующему

SwitchCurPosControl(t);// восстанавливаем значение переменной CurPosCtrl

}

Функции для работы с прерываниями СДК

void SetVect(unsigned char num, void code * handler) //установка вектора прерывания

{

unsigned char xdata * p = RAM_TABLE + (num << 3) + 3;//базовый адрес для прерывания от СОМ-порта

*p++ = LJMP;//заносим в память код команды LJMP

*(unsigned short xdata *)p = (unsigned short)handler;//в итоге по базовому адресу р находится команда ljmp COM_ISR

}

void COM_ISR(void) interrupt 4//обработчик прерывания от СОМ-порта

{

if(RI)//чтение из RS-232

{

switch(RSio())//читаем символ из порта

{

case 'Y'://если это символ Y то значит нажата кнопка ПУСК

{

start_process=TRUE;//разрешаем работу в функции main

LCD_Clear();//чистим дисплей

rrr=TRUE;//

break; //выход из switch

}

case 'N':// если это символ N то значит нажата кнопка СТОП

{

char stop_mes[]={0xa8,0x70,0x6f,0xe5,0x65,0x63,0x63,0x20,0x6f,0x63,0xbf,0x61,0xbd,0x6f,0xb3,0xbb,0x65,0xbd};//Строка «Процесс остановлен»

start_process=FALSE;//запрещаем работу в функции main

LCD_Clear();//чистим дисплей

LCD_Type(stop_mes);//вывод на дисплей«Процесс остановлен»

rrr=FALSE;//

i=1;//для светодиодов

break;// выход из switch

}

case 'M'://если это символ M то значит на катушке 500 кг проволоки

{

int h=0;//

char mes1[]={0x48,0x61,0x20,0xba,0x61,0xbf,0x79,0xc1,0xba,0x65,0x20,0x35,0x4f,0x4f,0xba,0xb4,0x20,0xbe,0x70,0x6f,0xb3,0x6f,0xbb,0x6f,0xba,0xb8};// Строка «На катушке 500 кг проволоки»

LCD_Clear();//чистим дисплей

LCD_Type(mes1);//вывод на дисплей «На катушке 500 кг проволоки»

Svetik(TRUE);//светодиоды потетрадно мигают

Buzz();//звук

LCD_Clear();//чистим дисплей

WriteMax(SV,0x00);//выключаем светодиоды

rrr=TRUE;//

start_process=FALSE;// запрещаем работу в функции main

i=1;//для светодиодов

for(;h<32000;h++) continue;//задержка

break;// выход из switch

}

case 'L'://если это символ L то значит на катушке 100 метров проволоки

{

char mes2[]={0x31,0x4f,0x4f,0x20,0xbc,0x65,0xbf,0x70,0x6f,0xb3,0x20,0xbe,0x70,0x6f,0xb3,0x6f,0xe3,0x61};//строка «100 метров провода»

int h=0;//

LCD_Type(mes2);// вывод на дисплей «100 метров провода»

Svetik(FALSE);//горят светодиоды

Buzz();//звук

for(;h<32000;h++) continue;// задержка

LCD_Clear();//чистим дисплей

WriteMax(SV,0x00);// выключаем светодиоды

break;// выход из switch

}

}

}

if(TI)// запись в RS-232

{

}

}

Функция MAIN

void main(void)//главная функция

{

Initilization();//инициализация системы

while(1)//бесконечный цикл

{

if(rrr) //если rrr=1

{

char start_mes[] = {0xA1,0x6f,0xbf,0x6f,0xb3,0xbd,0x6f,0x63,0xbf,0xc4,0x20,0xba,0x20,0xbe,0x79,0x63,0xba,0x79};// строка «Готовность к пуску»

LCD_Clear();//чистим дисплей

LCD_Type(start_mes);// вывод на дисплей «Готовность к пуску»

rrr=FALSE;//

}

if(start_process)//если нажата кнопка ПУСК то начинаем опрос датчиков(клавиатуры), иначе ждем нажатия кнопки ПУСК

{

if(ScanKBOnce(symbol_from_kb)==0x01)//если клавиша нажата

{

char sym=*symbol_from_kb;//то определяем, что это за клавиша

float voltage=0;//напряжение с толщиномера

switch(sym)//какая клавиша нажата

{

case '1': {// клавиша 1 (1 импульс)

Type("1");//в СОМ-порт отправляем символ

break;// выход из switch

}

case '2': {// клавиша 2 (10 импульсов)

Type("10");// в СОМ-порт отправляем символ

break;// выход из switch

}

case '3': { // клавиша 3 (100 импульсов)

Type("100");//

break;// выход из switch

}

case 'A': { // клавиша А (1000 импульс)

Type("1000");//

break;// выход из switch

}

case '4': {// клавиша 4 (10000 импульс)

Type("10000");//

break;// выход из switch

}

case '5': { // клавиша 5 (100000 импульс)

Type("100000");//

break;// выход из switch

}

case '6': { // клавиша 6 ( 0.0001 метра)

SetVoltage(0.2,DAC0);//АЦП

voltage=GetVoltage(0);//ЦАП

Type("0.0001");// в СОМ-порт отправляем диаметр.

break;// выход из switch

}

case '7': {// клавиша 7 ( -0.0001 метра)

SetVoltage(-0.2,DAC0);// АЦП

voltage=GetVoltage(0);// ЦАП

Type("-0.0001");//

break;// выход из switch

}

case '8': {// клавиша 8 ( 0.001 метра)

SetVoltage(1.2,DAC0);// АЦП

voltage=GetVoltage(0);// ЦАП

Type("0.001");//

break;// выход из switch

}

case '9': {// клавиша 9 ( -0.001 метра)

SetVoltage(-1.2,DAC0);// АЦП

voltage=GetVoltage(0);// ЦАП

Type("-0.001");//

break;// выход из switch

}

}//end switch

}

}

}//end while(1)

}//end main