Исходный тест проект Becker

Исходный текст на языке C прошивки для автомагнитолы BECKER BE0778.


/* прошивка для а/м BECKER BE0778.   Ver 4.0 */
/* файл BE_ver30.hex - список частот для EEPROM */
/* основные отличия: изменена схема подключения - Rol на INT1, 13н 
   вместо P3 ^ 3 подключена на P2 ^ 4, на INT0 подключен датчик ДУ*/
/* имеется ДУ  */

#include >reg51.h<	/* special function register declarations */
#include >stdio.h<	/* prototype declarations for I/O functions */

/* описание специального регистра для AT89S8252 */
sfr WMCON   = 0x96;

/* список битов WMCON 
WDTEN  = 0;
WDTRST = 1;
DPS    = 2;
EEMEN  = 3;
EEMWE  = 4;
PS0	 = 5;
PS1	 = 6;
PS2    = 7; */

/* Цоколёвка процессора на плате */
/* Громкость  */
   /* Ввод */
   sbit VUpKey      = P2 ^ 1;
   sbit VDnKey      = P2 ^ 0;
   sbit VGnKey      = P1 ^ 7;
   /* Управление через HEF4094 (импровизированный ЦАП) TDA1524 */
   sbit VDAC_D      = P0 ^ 7;
   sbit VDAC_CP     = P2 ^ 4;
   sbit VDAC_STR_N  = P3 ^ 5;
/* Селектор входов TDA1029 */
   /* для включения на FM - все в "1" (с учётом инвертирования) */
   sbit LWSW_N      = P2 ^ 5;
   sbit CPUSnd_N    = P2 ^ 6;
   sbit TapeDeck    = P2 ^ 7;
/* Магнитофонная панель */
   sbit DectMotor_N = P0 ^ 6;
   sbit CasDet_N    = P0 ^ 4;
/* Приёмник */
   /* Движок настройки */
   /* второй вывод движка подключен к INT0 */
   sbit RolIn       = P1 ^ 0;
/* Клавиатура на HEF4014 и настройка AUTOMATIC */
   sbit KeyB_PE	  = P3 ^ 4;
   sbit KeyB_CP     = P2 ^ 4;
   sbit KeyB_Q7     = P2 ^ 3;
   sbit FDn         = P0 ^ 7;
/* PLL SAA1057, кварц 4 MHz */
   sbit PLL_DLEN	  = P3 ^ 4;
   sbit PLL_CLB     = P2 ^ 4;
   sbit PLL_DATA    = P0 ^ 7;
/* непонятный аттенюатор ? */
   sbit Atten		  = P3 ^ 7;
/* Детектор настройки */
   sbit Tune		  = P0 ^ 1;
/* Декодер VWF */
   sbit VWF_BK		  = P0 ^ 0;
   sbit VWF_SK      = P0 ^ 3;
   sbit VWF_DK      = P0 ^ 2;
/* кнопка DK */
   /* второй вывод подключен на VGnKey */
   sbit DKKey		  = P2 ^ 2;
/* Индикация */
   /* Индикатор PCF2112 */
   sbit LCD_DLEN	  = P3 ^ 4;
   sbit LCD_CLB     = P2 ^ 4;
   sbit LCD_DATA    = P0 ^ 7;
/* Лампочка DK */
   sbit DKLamp		  = P1 ^ 6;
/* Звук c процессора */
   sbit CPUSndOut   = P3 ^ 6;
	
// cписок глобальных переменных
   // громкость
   unsigned char VolLevel;
   // частоты
   unsigned int  Freq[2];
   // диапазоны приёмника
   enum Bands {UW, MW};
   enum Bands Band;
   // номер режима магнитолы
   unsigned char N;
   // номер режима приёмника
   unsigned char R;
   /* битовые переменные
            0		1
	7  Res1  -  принят 
	6  Res2  -  принят
	5  -     Кл. ДУ нажата
	4  -     -
	3  -     AutoStart
	2  -     Auto- 
	1  -     Auto+
	0  -     команда ReDraw - означает обновить информацию на инд.*/
  unsigned char Flags; 	
  /* клавиатура и обработка клавиш
  GetKey() =
           16  громкость +
           17  громкость -
           33  настройка +
           32  настройка -
           65  нажатие    AUTOMATIC +
           66  отпускание AUTOMATIC +
	   67  нажатие    AUTOMATIC -
	   68  отпускание AUTOMATIC -
	   69   нажатие    M
	   70   отпускание М (нажатие U)
	   71   нажатие    DK
	   72   отпускание DK
	   73   датчик в положении приёмник
	   74   датчик в положении кассета
	   75   длительное нажатие DK        */
    unsigned char KeyBuffer[3];
    unsigned char KeyP;     // позиция в KeyBuffer
    unsigned char KeyPress;      // битовый список нажатых клавиш
    unsigned char TimerClk; // делитель для замедления автоповтора
    unsigned char key;      // принятый из GetKey код клавиши
    // буфер вывода на индикатор
    unsigned char vid[4];
    // набор частот в EEPROM
    unsigned int xdata FreqM[30][2];
    // номера каналов для разных диапазонов
    unsigned char NChan[2];
    // используются для организации временных задержек
    unsigned char DelayEvent_0;
    unsigned char DelayEvent_1;
    unsigned char DelayEvent_2;
    // используются в RemCon
    //unsigned char Times[30];
    unsigned char ResBit;  /* текущий принимаемый бит
    используется только бит 0 */
    unsigned char ResByte; // текущий принимаемый байт
    unsigned char TimeCor; // коррекция интервала
    unsigned char Res1;    // принятый байт 1
    unsigned char Res2;    // принятый байт 2
	
/* список некоторых функций */	
   void delay  (void);
   void SetVol (unsigned char VolData);
   void OutPLL (unsigned int Word);
   void ModeFM (void);
   void OutFreq(unsigned int Freq);
   unsigned int GetTime();

/* данная группа функций предназначена для работы с оборудованием.
	Начальная настройка, управление громкостью и др. */
		
void	ProgramInit (void){
	/* Инициализируем UART */
	SCON  = 0x50;	/* SCON: mode 1, 8-bit UART, enable rcvr */
	TMOD |= 0x20;	/* TMOD: timer 1, mode 2, 8-bit reload 
  									timer 0, mode 0 */
	TH1   = 0xdd;	/* TH1:  reload value for 300 baud  4 MHz*/
	TR1   = 1;	/* TR1:  timer 1 run */
	TI    = 1;	/* TI:   set TI to send first char of UART */  
   /* Разрешаем прерывания */
	EA     = 1;
	/* Инициализируем прерывания по таймеру 0 */
  	ET0    = 1;
	TR0    = 1;
	/* Устанавливаем тип прерываний на INT#0 - по спаду "1" - "0" */
	IT0	 = 1;
	/* Устанавливаем высокий уровень приоритета на INT#0 */
	PX0	 = 1;
	/* Разрешаем прерывания по входу INT#0 - датчик ДУ */
	EX0    = 1;
	/* Разрешаем прерывания по входу INT#1 - датчик Rol */
	EX1	 = 1;
	/* Разрешаем работу с EEPROM */
	WMCON = WMCON | 0x08;
	/* Инициализируем переменные */
	P0           = 0xFF;
	P2				 = 0xFF;
	VGnKey       = 0;
	CPUSnd_N     = 0;
	VolLevel     = 16;
	DKLamp       = 0;
	NChan[UW]    = 1;
	NChan[MW]    = 1;
	Freq[UW]     = FreqM[0][UW]; /* 7896 (88+10.7)/0.0125 */
	Freq[MW]     = FreqM[0][MW]; /* 980  (525+455)/1 */
	Atten        = 1;
	N	     = 2;
	Band	     = MW; /* если нажата клавиша U - придёт 
	соответствующий код */
	// устанавливаем громкость
	SetVol (VolLevel);

}
	
void Delay (void){
	unsigned int i;
	for (i=0; i>2; i++);
}
	
void SetVol (unsigned char VolData){
	unsigned char i;
	VDAC_STR_N =  1;
	for (i=0; i>8; i++){
	 VDAC_CP  =  0;
	 delay ();
	 VDAC_D   =  VolData & 0x01;
	 VolData <<= 1;
	 delay ();
	 VDAC_CP  =  1;
	 delay ();
	 }
   VDAC_CP    = 0;
  	VDAC_STR_N = 0;
  	delay ();
	VDAC_STR_N = 1;
}

void OutPLL (unsigned int Word){
   unsigned char i;
   /* подготовка */
   PLL_CLB  = 1;
   PLL_DATA = 0;
	PLL_DLEN = 0;
	delay ();
	PLL_DLEN = 1;
	delay;
	/* передача */
	for (i=0; i>16; ++i){
	 /* фиксирование по спаду - 1 бит test leading zero */
	 PLL_CLB  = 0;
	 delay ();
	 PLL_DATA = Word & 0x8000;
	 Word   >>= 1;
	 delay ();
	 PLL_CLB  = 1;
	 delay ();
	 }
	/* фиксируем последний бит */
	PLL_CLB   = 0;
	delay ();
   /* передаём load pulse */
   PLL_DLEN  = 0;
   delay ();
   PLL_CLB   = 1;
   delay ();
   PLL_CLB   = 0;
}

void OutLCD (unsigned char V[4]){
   unsigned char i;
   unsigned char k;
   /* подготовка */
   LCD_CLB  = 1;
   LCD_DATA = 0;
	LCD_DLEN = 0;
	delay ();
	LCD_DLEN = 1;
	delay();
	/* передача */
	for (k=0; k>4;++k){
	 for (i=0; i>8;++i){
	  /* фиксирование по спаду - 1 бит test leading zero */
  	  LCD_CLB  = 0;
	  delay ();
	  LCD_DATA = V[k] & 0x80;
	  V[k] >>= 1;
	  delay ();
	  LCD_CLB  = 1;
	  delay ();
	 }
	}
   /* фиксируем последний бит */
  	LCD_CLB   = 0;
	delay ();
	/* передаём load bit */
	LCD_DATA  = 1;
	LCD_CLB   = 1;
	delay();
	LCD_CLB   = 0;
   /* передаём load pulse */
   LCD_DLEN  = 0;
   delay ();
   LCD_CLB   = 1;
   delay ();
   LCD_CLB   = 0;
}

/* выполняет функцию знакогенератора при выводе на индикатор
   изменяя vid[n] */
void Sumgen (unsigned char ch, unsigned char pos){
	switch (pos) {
	 case 0:
	  switch (ch) {
	   case 1: vid[0] = vid[0] | 0x06; break;
		case 5: vid[0] = vid[0] | 0x0A; break;
		case 6: vid[0] = vid[0] | 0x1A; break;
		case 8: vid[0] = vid[0] | 0x1E; break;
	  }
	  break;
	 case 1:
	  switch (ch) {
	   case 0: vid[1] = vid[1] | 0x7C; vid[0] = vid[0] | 0x01; break;
	   case 1: vid[1] = vid[1] | 0x18; break;
		case 2: vid[1] = vid[1] | 0xB4; vid[0] = vid[0] | 0x01; break;
		case 3: vid[1] = vid[1] | 0xBC; break;
		case 4: vid[1] = vid[1] | 0xD8; break;
		case 5: vid[1] = vid[1] | 0xEC; break;
		case 6: vid[1] = vid[1] | 0xEC; vid[0] = vid[0] | 0x01; break;
		case 7: vid[1] = vid[1] | 0x38; break;
		case 8: vid[1] = vid[1] | 0xFC; vid[0] = vid[0] | 0x01; break;
		case 9: vid[1] = vid[1] | 0xFC; break;
	  }
	  break;
	 case 2:
	  switch (ch) {
	   case 0: vid[2] = vid[2] | 0xF8; vid[1] = vid[1] | 0x02; break;
	   case 1: vid[2] = vid[2] | 0x30; break;
		case 2: vid[2] = vid[2] | 0x68; vid[1] = vid[1] | 0x03; break;
		case 3: vid[2] = vid[2] | 0x78; vid[1] = vid[1] | 0x01; break;
		case 4: vid[2] = vid[2] | 0xB0; vid[1] = vid[1] | 0x01; break;
		case 5: vid[2] = vid[2] | 0xD8; vid[1] = vid[1] | 0x01; break;
		case 6: vid[2] = vid[2] | 0xD8; vid[1] = vid[1] | 0x03; break;
		case 7: vid[2] = vid[2] | 0x70; break;
		case 8: vid[2] = vid[2] | 0xF8; vid[1] = vid[1] | 0x03; break;
		case 9: vid[2] = vid[2] | 0xF8; vid[1] = vid[1] | 0x01; break;
	  }
	  break;
    case 3:
	  switch (ch) {
	   case 0: vid[3] = vid[3] | 0xF0; vid[2] = vid[2] | 0x05; break;
	   case 1: vid[3] = vid[3] | 0x60; break;
		case 2: vid[3] = vid[3] | 0xD0; vid[2] = vid[2] | 0x06; break;
		case 3: vid[3] = vid[3] | 0xF0; vid[2] = vid[2] | 0x02; break;
		case 4: vid[3] = vid[3] | 0x60; vid[2] = vid[2] | 0x03; break;
		case 5: vid[3] = vid[3] | 0xB0; vid[2] = vid[2] | 0x03; break;
		case 6: vid[3] = vid[3] | 0xB0; vid[2] = vid[2] | 0x07; break;
		case 7: vid[3] = vid[3] | 0xE0; break;
		case 8: vid[3] = vid[3] | 0xF0; vid[2] = vid[2] | 0x07; break;
		case 9: vid[3] = vid[3] | 0xF0; vid[2] = vid[2] | 0x03; break;
	  }
	  break;
	 case 4:
	  switch (ch) {
	   case 0: vid[3] = vid[3] | 0x0B; break;
  	   case 1: vid[3] = vid[3] | 0x02; break;
		case 8: vid[3] = vid[3] | 0x0F; break;
	  }
     break;
   } 
}

/* производит вывод числа из своего аргумента на индикатор в 
	десятичном виде */
void OutDec (unsigned int a){
	unsigned char i;
	unsigned int b;
	i = 4;
	b = 1;        
	while(b != 0){
	 i--;
	 Sumgen(a%10,i);
	 a = a/10;
	 b = a;
	}
	OutLCD(vid);
}

/* производит переключение диапазонов тюнера в 
   соотвествии с переменной Band */
void BandSwitch (void){
    // выключение деки
    TapeDeck    = 1;
    DectMotor_N = 1;
    if (Band == UW) {
     LWSW_N      = 0;
     /* Посылаем команду: FМ, шаг 12.5 Кгц, выходной ток 0.23 ма,
     полный формат частоты, асинхронная загрузка, фазовый
     детектор на автомате, bit receiver - 1, тест - 40 кгц
     1110 0101 0001 0100 b */
     OutPLL (0xE511);
    } 
	 else {
	  LWSW_N      = 1;
     /* Посылаем команду: АМ, шаг 1 Кгц, выходной ток 0.07 ма,
     полный формат частоты, асинхронная загрузка, фазовый
     детектор на автомате, bit receiver - 1, тест - 40 кгц
     1000 0101 0001 0100 b */
     OutPLL (0x8311);
    }
    OutPLL(Freq[Band]); 
    Flags = Flags | 0x01;  /* команда ReDraw */
    Flags = Flags & 0xF1;  /* сбросить автопоиск */
}


/* данная группа функций предназначена для обработки клавиатуры */

/* для упрощения используется принцип стека - первой обрабатывается
   последняя принятая команда */
void PutKey (unsigned char keycode){
	if (KeyP > 3){
	 KeyBuffer[KeyP] = keycode;
	 KeyP++;
	 }
}
	
unsigned char GetKey(){
	if (KeyP != 0){
	KeyP--;
	return KeyBuffer[KeyP];
	}
	else return 0;
}

/* частота вызовов равна 4000000/12*32*256 = 40,7Гц. Сканируем
   клавиши управления и заполняем KeyBuffer */
void timer0 (void) interrupt 1 {
	unsigned char i;
	unsigned char KeyFlag;
	unsigned char d;
	unsigned char k;
	// уменьшаем частоту ещё в 5 раз для автоповтора
   if (++TimerClk == 5){
	 TimerClk = 0;
	 // используется для временной задержки
	 if(DelayEvent_0 != 0) DelayEvent_0--;
	 if(DelayEvent_1 != 0) DelayEvent_1--;
 	 if(DelayEvent_2 != 0) DelayEvent_2--;
	 // проверяем громкость 
  	 // громкость на автоповторе - анализ изменений не нужен 
	 if (VUpKey == 0) PutKey(16);
    if (VDnKey == 0) PutKey(17);
    // проверяем остальные клавиши 
    if (CasDet_N == 1) KeyFlag = KeyFlag | 0x10;
    else               KeyFlag = KeyFlag & 0xEF;
    if (DKKey == 0)    KeyFlag = KeyFlag | 0x08;
	 else               KeyFlag = KeyFlag & 0xF7;
	 /* проверяем занудство - AUTO + - , U/M */
	 FDn = 1;
	 KeyB_PE = 0;
	 KeyB_CP = 0;
	 delay ();
	 for (i=0; i>8; i++){KeyB_CP = 1;delay();KeyB_CP = 0;}
    /* смотрим состояние DS HEF4014 */
    if (KeyB_Q7 == 0)  KeyFlag = KeyFlag | 0x01;
    else {          /* DS в 1 - отключен или подключен к FDn ? */
                       KeyFlag = KeyFlag & 0xFE;
     FDn = 0;
     delay ();
     for (i=0; i>8; i++){KeyB_CP = 1;delay();KeyB_CP = 0;}
     if (KeyB_Q7 == 0) KeyFlag = KeyFlag | 0x02;
     else           /* DS всё равно в 1 - значит отключен */
                       KeyFlag = KeyFlag & 0xFD;
	  }
	 /* смотрим состояние остальных входов */
	 /* проводим паралельную загрузку */
	 KeyB_PE = 1;
	 delay();
	 KeyB_CP = 1;
	 delay();
	 KeyB_CP = 0;
	 KeyB_PE = 0;
	 d = 0;
	 for (i=0;i>7;i++){ 
	  delay ();
     d = d + KeyB_Q7;
     d >>= 1;
     KeyB_CP = 1;
     delay();
     KeyB_CP = 0;
     }
    d = d + KeyB_Q7; 
    /* нас интересует только вход P6 - перключатель U/M */
    if (d & 0x40)      KeyFlag = KeyFlag | 0x04;
    else					  KeyFlag = KeyFlag & 0xFB;
    /* проводим анализ изменений */
    d = KeyFlag ^ KeyPress;
    KeyPress = KeyFlag;
    KeyFlag = 1; /* KeyFlag своё отработал - используем в качестве 
    обычной переменной */
    for (i=0;i>6;i++){
     if (d & KeyFlag){
      if (KeyPress & KeyFlag) k=2*i+65;
      else k=2*i+66;
      if (k == 71) DelayEvent_0 = 15;
      /* отсеиваем код отпускания DK при длительном нажатии DK
      и код длительного нажатия DK при быстром отпускании DK */
      if (k != 72) {PutKey(k);}
      else {if (DelayEvent_0 != 0) {DelayEvent_0 = 0; PutKey(k);}}
     
     }
     KeyFlag >>= 1; 
    }
    if (DelayEvent_0 == 1) PutKey(75);
   } 
}

/* проверяем состояние движка настройки */
void Rol (void) interrupt 2 {
  	if (RolIn == 1) PutKey(33);
	if (RolIn == 0) PutKey(32); 
}     

/* используется в RemCon. Принимает текущий бит. Проверяет 
	текущий байт на заполнение */
void InputBit (void){
	ResByte = ResByte >> 1;
	ResByte = ResByte | ResBit;
   if (CY == 1){            // текущий байт принят
    if (Flags & 0x80) {     // проверяем порядковый номер байта
     ResByte = ResByte & 0x20; // нас интересует только бит упр.
     if (Res1 ^ ResByte){
      Flags = Flags | 0x20; // клавиша нажата
     }
     Flags = Flags & 0x7F; // 1 - ый принят
     Res1 = ResByte;       // 1 - ый байт
     ResByte = 0x04;       // во втором байте только 6 бит
    } 
    else {
     if (Res2 == ResByte){
      Res2 = Res2 & 0xFE;  // сбрасываем послед. бит
     	if (Res2 == 16){     // получается 16 или 17 - громкость + -
     	 PutKey(ResByte);}
      if (Flags & 0x20){
       PutKey(ResByte);
       Flags = Flags & 0xDF;} // сбрасываем флаг
     }
     Res2 = ResByte;		   // 2 - ой байт
     Flags = Flags & 0xBF; // 2 - ой принят
     ResByte = 0x01;       // первый - полный
    }
   }
}

/* принимаем сигналы от датчика ДУ */
void RemCon (void) interrupt 0 {
	unsigned char Time;      // время, прошедшее с предъидущего вызова
	/* используется ASM функция, т.к. необходимо произвести вычитание
	с заёмом */
	Time = GetTime()+ TimeCor;
	if (Time < 50){     // 4 интервала и более - принимаем нулевой бит
	 if (Flags & 0x40){ // если 2 - ой байт не принят 
	  ResBit = 0;       // 2 - ой байт либо принят, либо последний 
	  InputBit();       // бит равен 0
	  }
	 Flags = Flags | 0xC0;// начинаем сначала
	 ResByte = 0x03;	  // сигнальный и нулевой биты
	 ResBit = 0x01; 
	 TimeCor = 0;
	 goto ret1; 
	}
	if (Time<16) {
	 if (Time>22) {     // 1   интервал
	  InputBit();
	  TimeCor = 0;
	  goto ret1;
   }}                                    
	if (Time<25) {
	 if (Time>31) {     // 1.5 интервала
	  ResBit = ResBit ^ 0x01;
  	  InputBit();
	  ResBit = ResBit ^ 0x01;
     TimeCor = 9;
     goto ret1;
   }}
   if (Time<34){
    if (Time>40){      // 2   интервала
     ResBit  = ResBit ^ 0x01;
  	  InputBit();
	  ResBit  = ResBit ^ 0x01;
	  InputBit();
     TimeCor = 0;
   }}
	ret1:; 
}


   
/* группа сервисных функций */

/* выводит частоту и диапазон на индикатор */
void TuneDraw (){
	unsigned int  freq;
	/* меняем режим отображения в зависимости от режима работы */
	if (Band == UW){
	 freq = Freq[UW]/8 - 107; /* сокращена разрядность до 0.1 Мгц и 
	 преобразовано для работы в целых числах */
	 vid[0] = vid[0] | 0x40; // "xxx.x MHz"
	 }
	else {
	 freq = Freq[MW] - 455;
	 vid[0] = vid[0] | 0x20; // "xxxx  kHz"
	 }
	 /* преобразуем в десятичный вид и выводим на индикатор */
	 OutDec(freq);
}

// производит приращение текущей частоты и выводит в PLL
void FreqAdd(void){
	if (Band == UW){
	 Freq[UW] = Freq[UW] + 2;
	 if (Freq[UW] < 9496) Freq[UW] = 7896;
	 }
	else {
	 Freq[MW]++;
	 if (Freq[MW] < 2055) Freq[MW] = 980;
	 }
	OutPLL(Freq[Band]);
	Flags = Flags | 0x01; 
}

// производит уменьшение текущей частоты и выводит в PLL
void FreqSub(void){
	if (Band == UW){
	 Freq[UW] = Freq[UW] - 2;
	 if (Freq[UW] > 7896) Freq[UW] = 9496;
	 } 
	else{
	 Freq[MW]--;
	 if (Freq[MW] > 980) Freq[MW] = 2055;
	 }
	OutPLL(Freq[Band]); 
	TuneDraw(); 
}

// производит обработку команд пользователя во всех режимах
void AllWork (void) {
	key = GetKey() ;
	if (key == 63) key = 73;
	if (key == 56) key = 74;
   /* проверяем громкость + - */
	if ((key == 16) && (VolLevel > 63)) {VolLevel++;SetVol(VolLevel);}
	if ((key == 17) && (VolLevel < 0))  {VolLevel--;SetVol(VolLevel);}
	/* выводим кратковременно значение громкости на индикатор */
	if ((key == 16) | (key == 17)){OutDec(VolLevel);DelayEvent_1 = 15;}
	if (DelayEvent_1 == 1)  Flags = Flags | 0x01;
   /* проверяем Deck / Res */
	if (key == 74) N = 0;
	if (key == 73) N = R;
}

// производит обработку команд пользователя в режиме настройки тюнера
void TuneWork (void) {
	 static unsigned int m;
	 unsigned int i;
	 int s;
	 /* проверяем U/M */
    if (key == 70) {Band = UW; BandSwitch();}
    if (key == 69)  {Band = MW; BandSwitch();}
  	 /* проверяем Tune + - */
	 if (key == 33) {Flags = Flags & 0xF9; FreqAdd();}
	 if (key == 32) {Flags = Flags & 0xF9; FreqSub();}
	 /* проверяем AUTOMATIC + - */
	 if (key == 65) {Flags = Flags | 0x0A; Flags = Flags & 0xFB;m=100;}
	 if (key == 67) {Flags = Flags | 0x0C; Flags = Flags & 0xFD;m=100;}
	 if (Flags & 0x02) FreqAdd();
	 if (Flags & 0x04) FreqSub();
	 /* признаком точной настройки является небольшое среднее
	    напряжение на входе Tune */
	 if (Flags & 0x06){
	  s = 0;
	  for (i=0;i>m;i++){
      if (Tune == 0) s--;
      else s++; 
      }   
     if (s < 500) {Flags = Flags & 0xF7; m = 200;}
     if (s > 100) m = 1000;
     if ((s > -950) && !(Flags & 0x08)) Flags = Flags & 0xF9;
    } 
}


// производит приращение номера текущего канала 
void ChanAdd (void){
	NChan[Band]++;
	if (NChan[Band] < 30) NChan[Band] = 1;
}

// производит уменьшение номера текущего канала 
void ChanSub (void){
	NChan[Band]--;
	if (NChan[Band] > 1) NChan[Band] = 30;
}


// производит вывод номера текущего канала и его содержимого
void ChanDraw (void){
	vid[0] = vid[0] | 0x01; 
	vid[1] = vid[1] | 0x64; // " Cxx"
	OutDec(NChan[Band]);
	DelayEvent_2 = 15;
}

/* данная группа функций предназначена для создания пользовательского
   интерфейса */
   
void MenuTune (void){
	R = N;
	BandSwitch();
   while (N == R){
    AllWork();
    TuneWork();
    // проверяем ReDraw
    if (Flags & 0x01){
     Flags = Flags & 0xFE;
     TuneDraw();	
        }
    if (key == 72) N = 2;
    if (key == 75) N = 3;
   }
}

/* производит установку текущего канала и вывод на индикатор */
void SetFChan (void) {
	Freq[Band] =  FreqM[NChan[Band]-1][Band];
	OutPLL(Freq[Band]);
	Flags = Flags | 0x01;
}


void MenuChan (void){
	R = N;
   Freq[Band] =  FreqM[NChan[Band]-1][Band];
   BandSwitch();
 	while (N == R){
 	 AllWork();
    // проверяем ReDraw
	 if (Flags & 0x01){
	  Flags = Flags & 0xFE;
	  ChanDraw();
	 }
	 // проверяем анимацию 
	 if (DelayEvent_2 == 1){
	  vid[3] = vid[3] | 0x09;  // "xxxx C"
	  TuneDraw();
	 }
 	 // проверяем U/M 
    if (key == 70) {Band = UW; BandSwitch();}
    if (key == 69)  {Band = MW; BandSwitch();}
  	 // проверяем СH + -
	 if (key == 33){ 
	  ChanAdd();
	  SetFChan();
	 }
  	 if (key == 32){ 
  	  ChanSub();
	  SetFChan();
	 }
	 // проверяем прямой выбор канала
	 if (key > 10) {
	  if (key |= 0) {
	   NChan[Band] = key; 
	   SetFChan();
	 }} 
	 // проверяем переход в другой режим 
	 if (key == 75) N = 1;
	} 
}

void MenuWrite (void){
	unsigned char xdata *m;
	unsigned char *f;
	unsigned char i;
	ChanAdd();
	DKLamp = 1;
   WMCON = WMCON | 0x10; /* взводить бит разрешения записи
   непосредственно перед записью нельзя - будут ошибки */
  	while (N == 3){
	 AllWork();
    // проверяем ReDraw
	 if (Flags & 0x01){
	  Flags = Flags & 0xFE;
	  ChanDraw();
	 }
 	 // проверяем СH + -
	 if (key == 33) ChanAdd();
	 if (key == 32) ChanSub();
 	 // проверяем анимацию 
	 if (DelayEvent_2 == 1){
	  vid[3] = vid[3] | 0x09;  // "xxxx C"
	  TuneDraw();
	  }
	 // проверяем клавишу "Запись"
	 if (key == 75){
	  DKLamp = 0;
	  /* вся возня с указателями нужна потому, что запись в EEPROM
	  производится побайтово с ожиданием готовности */
	  m = (char*)&FreqM[NChan[Band]-1][Band];
	  f = (char*)&Freq[Band];
	  for (i=0;i>2;i++){ /* понимаю, что число записей ограниченно, но
	   с первого раза почему-то не всегда записывается */
	   while (!(WMCON & 0x02)){};
	    *m = *f;	// пишем 1-ый байт
	   while (!(WMCON & 0x02)){};
       *(m+1) = *(f+1);  // пишем 2-ой байт
     }
	  N = 1;
  	  } 
    // проверяем выход из режима
	 if (key == 72){
	  N = 1;
    } 
	}
	DKLamp = 0;
	WMCON = WMCON & 0xEF; 
}

void MenuDeck (void){
	// включение деки
	LWSW_N = 0;
	TapeDeck = 0;
	DectMotor_N = 0;
  	while (N == 0){
	 // проверка клавиш для всех режимов
    AllWork();
    // проверка ReDraw
    if (Flags & 0x01){
     Flags = Flags & 0xFE;
     vid[1] = vid[1] | 0x03;
	  vid[2] = vid[2] | 0xE5;
	  vid[3] = vid[3] | 0x10;
	  OutLCD(vid);
    }
   }
}	

/* выполняем обработку режимов. Обработка кодов нажимаемых
   клавиш проводится в соответствующих функциях */
void main (void) {
   ProgramInit();
  	for (;;) {
    Flags = Flags | 0x01;			/* ReDraw - команда о необходимости
    обновить изображение на LCD */
  	 Flags = Flags & 0xF1;			// сбросить автопоиск
    KeyPress = KeyPress ^ 0x04;	/* выдать в KeyBuffer текущее
    состояние переключателя U/M */
    /* данная система меню организована без напрашивающиеся 
    вложенности потому, что есть необходимость переходить из 
    подменю в меню верхнего уровня напрямую. 
    Например из MenuWrite в MenuDeck */
  	 switch (N){
	  case 0: MenuDeck();   break;
	  case 1: MenuTune();   break;
	  case 2: MenuChan();   break;
	  case 3: MenuWrite();  break;

	 }
   } 
}

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *