⚠ 11.2023: Сайт знаходиться в стані перебудови. Можливо тимчасове порушення функціонування.

Зовнішній дисплей для ПК з апаратним декодером сигналів пульта дистанційного керування

Завдяки BadMojoX, який створив plugin Dir (Display & control device, популярна мультимедійна оболонка MediaPortal отримала можливість виводити додаткову інформацію на зовнішній LCD-дисплей, а також апаратно розпізнавати сигнали з пульта дистанційного керування.

Питання щодо роботи plugin можна задавати у спеціальній гілці форуму:Dir (Display & IR) control device

Модифікована версія приставки з інтерфейсом USB на PIC18F14K50.


Налаштування плагіна

Для перегляду та прослуховування мультимедіа я спорудив окремий ПК на базі Intel Celeron 1200 Tualatin із встановленою оболонкою Media Portal. Ця оболонка дуже схожа на Windows Media Center, але має більш широкі можливості, безкоштовна та має безліч плагінів.

Пристрій насамперед призначений для відображення на текстовому дисплеї додаткової інформації (тривалість відтворення, ім'я файлу, що відтворюється, MP3 ID теги, активний телеканал і багато іншого, а також приймати сигнали пульта дистанційного керування (декодуванням займається МК) і відправляти декодовані команди плагіну. В режимі очікування я вирішив виводити на дисплей поточний час, дату, день тижня та температуру. Заради інтересу я також влаштував на другому рядку дисплея, інформація для якого знаходиться у встановленій на платі зовнішньої флеш-пам'яті. Тобто, можна попередньо записати з ПК туди якусь інформацію (наприклад, прогноз погоди на тиждень) і вона буде прокручуватись там.

Насамперед наведу зміст оригінального файлу interface.h, в якому описані всі команди, що використовуються при обміні даними між плагіном та приставкою. Власне весь вихідний текст виходить з цього список команд. Зеленим кольором виділено команди, які підтримуються моєю версією приставки. На решту команд приставка відповідає "CMD_UNKNOWN" або робить вигляд, що прийняла її (залежно від команди).

#ifndef INTERFACE_H
#define INTERFACE_H

// each command consists from a single command byte
// and from command parameters, which follow the command.
// The count of parameters is command dependent.
// Each command sent from the computer will be aknowledged by the hardware: CMD_ACCEPTED, Command ID
// If command contains wrong parameter or the command id is unknown, the hardware answers with: CMD_UNKNOWN,CommandID.

#define NO_CMD 0x00 // no current command

#define CMD_PING 0x01 // pings board.
// To board: CMD_PING, From board: CMD_ACCEPTED, CMD_PING = (Aknowledge)
#define CMD_ACCEPTED 0x02 // reports accepted command following by the command code
#define CMD_IR_CODE 0x03 // notyfies the computer about a key pressed on the remote control.
// To board: -, From board: (Aknowledge), CMD_IR_CODE, KeyCode
#define CMD_POWERDOWN 0x04 // power down. Notyfies the hardware that the computer will be switched off.
// To board: CMD_POWERDOWN, From board: (Aknowledge)
#define CMD_SET_ON_STATE 0x05 // followed by the power on state, used to display different states.
// To board: CMD_SET_ON_STATE, State (1 byte), From board: (Aknowledge)
// State byte description:
// DISPLAY_STATE 0 - use state
// DISPLAY_TIME 1 - display current time
// DISPLAY_ALARM 2 - display alarm symbol
// DISPLAY_REC 3 - display rec. symbol
// DISPLAY_DATE1 4 date format to display (00- no date)
// DISPLAY_DATE2 5
// DISPLAY_BRIGHTNESS 6 - display LCD brightness in % (only offline mode)
#define CMD_SET_OFF_STATE 0x06 // followed by the power on state , used to display different states
// To board: CMD_SET_ON_STATE, State (1 byte), From board: (Aknowledge), State byte is the same
// as for CMD_SET_ON_STATE.
#define CMD_SET_LED 0x07 // followed by the led state
// To board: CMD_SET_LED, Led state (0/1) From board: (Aknowledge)
#define CMD_GET_BR_ITEM 0x08 // followed by the position
// To board: CMD_GET_BR_ITEM, Position (0...)
// From board: if the entry exists then (Aknowledge) and informations
// From time (Hour, Min) (2 bytes), To time (Hour, Min) (2 bytes), 2 Bytes brightness (| 0x8000 if the entry is valid and used).
// From board: if the entry does not exist then: CMD_UNKNOWN, CMD_GET_BR_ITEM = (Failed)
#define CMD_SET_BR_ITEM 0x09 // followed by the position index + from time + to time + brightness
// To board: CMD_SET_BR_ITEM, Index, 6 data bytes. From board: (Aknowledge) or (Failed)
#define CMD_GET_ON_STATE 0x0A // get on common state
// To board: CMD_GET_ON_STATE, From board: (Aknowledge), CMD_GET_ON_STATE, State (1 byte)
#define CMD_GET_OFF_STATE 0x0B // get off common state
// To board: CMD_GET_OFF_STATE, From board: (Aknowledge), CMD_GET_OFF_STATE, State (1 byte)
#define CMD_GET_LED 0x0C // returns led state
// To board: CMD_GET_LED, From board: (Aknowledge), CMD_LED, State (1 byte)
#define CMD_CHECK_BR_TABLE 0x0D // reset stored minutes to check the brightness from the table
// To board: CMD_CHECK_BR_TABLE, From board: (Aknowledge)
#define CMD_GET_POWER_DELAY 0x0E // returns power change delay in seconds
// To board: CMD_GET_POWER_DELAY, From board: (Aknowledge), CMD_GET_POWER_DELAY, Delay (1 byte)
#define CMD_SET_POWER_DELAY 0x0F // set power delay in seconds
// To board: CMD_SET_POWER_DELAY, Delay (1 byte), From board: (Aknowledge)
#define CMD_SET_HOUR 0x10 // set hour
// To board: CMD_SET_HOUR, Hour (1 byte), From board: (Aknowledge)
#define CMD_SET_MIN 0x11 // set min
// To board: CMD_SET_MIN, Min (1 byte), From board: (Aknowledge)
#define CMD_SET_SEC 0x12 // set sec
// To board: CMD_SET_SEC, Sec (1 byte), From board: (Aknowledge)
#define CMD_SET_DAY 0x13 // set day
// To board: CMD_SET_DAY, Day (1 byte), From board: (Aknowledge)
#define CMD_SET_MON 0x14 // set month
// To board: CMD_SET_MON, Min (1 byte), From board: (Aknowledge)
#define CMD_SET_YEAR 0x15 //21 set year
// To board: CMD_SET_YEAR, Year (2 bytes), From board: (Aknowledge)
#define CMD_SET_WEEK 0x35 // set day of week
// To board: CMD_SET_WEEK, week (1 byte), From board: (Aknowledge)
#define CMD_SET_ALARM 0x16 // set alarm to hour, min, day, month
// To board: CMD_SET_ALARM, Hour (1byte), Min (1byte), Day (1byte), Month(1 byte), From board: (Aknowledge)
#define CMD_ALARM_ENABLE 0x17 // enable alarm, 0 - disable, 1-enable
// To board: CMD_ALARM_ENABLE, Enable/Disable (1 byte), From board: (Aknowledge)
#define CMD_LCD_CLEAR 0x20 // lcd clrscr
// To board: CMD_LCD_CLEAR, From board: (Aknowledge)
#define CMD_LCD_HOME 0x21 // lcd home
// To board: CMD_LCD_HOME, From board: (Aknowledge)
#define CMD_LCD_GOTO 0x22 // lcd goto
// To board: CMD_LCD_GOTO, Position (1byte), From board: (Aknowledge)
#define CMD_LCD_TEXT 0x23 // followed by a string, terminated by 0
// To board: CMD_LCD_TEXT, Text, 0, From board: (Aknowledge)
#define CMD_LCD_CGRAM 0x24 // programm cgram, address, then the values
#define CMD_LCD_BRIGHT 0x25 // sets the immediate lcd brightness

#define CMD_W_EXT_FLASH 0x30 // Write data to external EEPROM //To board: CMD_W_EXT_FLASH, Text, 0, From board: (Aknowledge)
//0 = 48
// To board: CMD_LCD_BRIGHT, Brightness (2 bytes), From board: (Aknowledge)
#define CMD_GET_BOARD_ID 0x80 //returns command accepted followed by two bytes 0xAA55
// To board: CMD_GET_BOARD_ID, From board: (Aknowledge), CMD_GET_BOARD_ID, 0xAA55
#define CMD_GET_BOARD_HW 0x81 //returns command accepted followed by two bytes HW Version
// To board: CMD_GET_BOARD_HW, From board: (Aknowledge), CMD_GET_BOARD_HW, (HW Version) 2 bytes
#define CMD_GET_BOARD_SW 0x82 // returns command accepted followed by two bytes SW Version
// To board: CMD_GET_BOARD_SW, From board: (Aknowledge), CMD_GET_BOARD_SW, (SW Version) 2 bytes

#define CMD_GET_BOARD_INFO 0x83 // returns command accepted followed by command id + board information text terminated by 0 character
// To board: CMD_GET_BOARD_INFO, From board: (Acknowledge), CMD_GET_BOARD_INFO, Text, 0 character

#define CMD_UNKNOWN 0xFF // unknown command

#define BOARD_ID_LO 0x55
#define BOARD_ID_HI 0xAA

#define BOARD_HW_LO 0x00
#define BOARD_HW_HI 0x01

#define BOARD_SW_LO 0x02
#define BOARD_SW_HI 0x00
#endif

Робота з плагіном дуже проста. Достатньо правильно відповідати на отримані команди. Як зазначено вище, при отриманні приставкою команди вона має надіслати команду CMD_ACCEPTED і далі переслати отриманий код команди. Наприклад, на команду CMD_PING приставка має відповісти CMD_ACCEPTED CMD_PING.

З огляду на це вдалося отримати досить просту функцію обробки команд, написану мовою Сі:

void fn_CMD_ACCEPTED(unsigned char key)
{
putc(CMD_ACCEPTED);
putc(key);
}
......

if (FIFOsize>0) key=ReadFIFO(); else key=0;
   //FIFO - буфер приема UART.
switch(key) {
     case NO_CMD : break;
     case CMD_PING : fn_CMD_ACCEPTED(CMD_PING); break; //Ping
     case CMD_SET_ON_STATE: putc(CMD_UNKNOWN); putc(key); StandBy=0; break;
     case CMD_SET_OFF_STATE:fn_CMD_SET_STATE(CMD_SET_OFF_STATE); break;
     case CMD_SET_LED : ReadFIFO(); fn_CMD_ACCEPTED(CMD_SET_LED); break;
     case CMD_GET_ON_STATE: putc(CMD_UNKNOWN); putc(key); break;
     case CMD_SET_HOUR : hour=ReadFIFO(); fn_CMD_ACCEPTED(CMD_SET_HOUR); AdditionalInfo=RefreshClock=3; break;
     case CMD_SET_MIN : min=ReadFIFO(); fn_CMD_ACCEPTED(CMD_SET_MIN); AdditionalInfo=RefreshClock=3; break;
     case CMD_SET_SEC : sec=ReadFIFO(); fn_CMD_ACCEPTED(CMD_SET_SEC); AdditionalInfo=RefreshClock=3; break;
     case CMD_SET_DAY : day=ReadFIFO(); fn_CMD_ACCEPTED(CMD_SET_DAY); AdditionalInfo=RefreshClock=3; break;
     case CMD_SET_MON : mon=ReadFIFO(); fn_CMD_ACCEPTED(CMD_SET_MON); AdditionalInfo=RefreshClock=3; break;
     case CMD_SET_YEAR : fn_CMD_SET_YEAR(); AdditionalInfo=RefreshClock=3; break;
     case CMD_SET_WEEK : week=ReadFIFO(); fn_CMD_ACCEPTED(CMD_SET_WEEK); AdditionalInfo=RefreshClock=3; break;

     case CMD_LCD_CLEAR : DisplayClear(); break;
     case CMD_LCD_HOME : LCDGoTo(0); fn_CMD_ACCEPTED(CMD_LCD_HOME); break;
     case CMD_LCD_GOTO : LCDGoTo(ReadFIFO()); fn_CMD_ACCEPTED(CMD_LCD_GOTO); break;
     case CMD_LCD_TEXT : LCDTextOut(); fn_CMD_ACCEPTED(CMD_LCD_TEXT); StandBy=0; break;
     case CMD_GET_BOARD_ID:fn_CMD_ACCEPTED(CMD_GET_BOARD_ID); putc(CMD_GET_BOARD_ID); putc(BOARD_ID_LO); putc(BOARD_ID_HI); break;
     case CMD_GET_BOARD_HW:fn_CMD_ACCEPTED(CMD_GET_BOARD_HW); putc(CMD_GET_BOARD_HW); putc(0x01); putc(0x00); break;
     case CMD_GET_BOARD_SW:fn_CMD_ACCEPTED(CMD_GET_BOARD_SW); putc(CMD_GET_BOARD_SW); putc(0x02); putc(0x00); break;
     case CMD_GET_BOARD_INFO:fn_CMD_ACCEPTED(CMD_GET_BOARD_INFO); putc(CMD_GET_BOARD_INFO); putc(0x33); putc(0x34); putc(0x35); putc(0x00); break;

     case CMD_W_EXT_FLASH: WriteExternalFlash(); fn_CMD_ACCEPTED(CMD_W_EXT_FLASH);      break;

     default : putc(CMD_UNKNOWN); putc(key); ShowError(key); break;

Приставка побудована на базі мікроконтролера PIC16F887 (вдосконалена версія PIC16F877A, корпус DIP40), працює на частоті 4 МГц (кварцевий резонатор). Перетворювач RS232-UART - MAX232CPE, мікросхема годинника (RTC) DS1307 (DIP8, I2C), EEPROM-пам'ять - 24AA32 (DIP8, I2C, 32кбіта, підходить на любий об'єм, прив'язки в прошивці немає. Це для інформації в другому рядку).

Схема приставки для ПК. Тектовий LCD-дисплей, приймач IR сигналів пульта дистанційного керування
Схема, в форматі sPlan 5.

Щоб заощадити на батарейках :) я встановив в схему живлення годинника реального часу DS1307 іоністор ємністю 0.1F (5.1V). Заряду впевнено достатньо на кілька тижнів роботи без зовнішнього живлення, більше в мене не було можливості перевірити (жити без приставки не можу :)). Для підзарядки використовується подільник напруги на двох резисторах і захистному діоді, що запобігає розряду через схему.

Після довгих роздумів, як дисплей був обраний BC2002BFNLCH з зеленим інверсним підсвічуванням та висотою символів 9.6 мм.

Щоб зробити приставку компактною, я спроектував друковану плату таких самих розмірів, як і сам дисплей, що дозволило встановити її за ним.

Зовнішній вигляд приставки-дисплея на базі LCD BC2002B PIC16F887 (PIC16F877A)

Друкована плата виготовлялася за ЛУТ-технологією:

Плата приставки для ПК на PIC16F887

Плата в форматі SprintLayout 5.0.

Зворотня сторона

BC2002B

У прошивці встановлена швидкість 9600 кбіт/с (без бітів контролю парності, один стоповий біт).

Прошивка: build 31 (04.05.09) Прошивка.hex (PIC16F887)



Додоміжні матеріали

Файл "DirControlDevicePlugin.DisplayStates.xml" містить оформлення інформації, що виводиться на дисплей. Мій файл розрахований на дисплей 20x2:


Файл "DirControlDevicePlugin.Cyrylic.CharacterTranslations.xml" містить таблицю перетворення кириличних символів з кодування UTF-8 (ну і win-1251) в кириличне кодування зашите в LCD-дисплей на контролері типу HD44780 (KS0066U). У зв'язку з тим, що стандартна таблиця символів контролера HD44780 (KS0066U) не містить українських символів, вони завантажуються програмно після подачі живлення.


Файл "DirControlDevicePlugin.DisplayTypes.xml" містить геометрію Вашого LCD-дисплея (8x1, 16x2, 0x20). Файл легко підправити вручну під дисплей.

Ці файли слід покласти поруч із файлом плагіна.

Демонстрація роботи плагіна та приставки


Вихідний код для PIC16F887


1.///Версия прошивки:
2.#define  BuildVer "\fDISPLAY v1.0\nbuild 31 (04.05.09)"
3. 
4.#include <16F887.h>
5.#include "interface.h"
6. 
7.#device *=16
8.#device adc=8
9. 
10. 
11.#FUSES WDT                      //Watch Dog Timer
12.#FUSES XT                       //Crystal osc <= 4mhz
13.#FUSES PUT                      //Power Up Timer
14.#FUSES MCLR                     //Master Clear pin enabled
15.#FUSES NOPROTECT                //Code not protected from reading
16.#FUSES NOCPD                    //No EE protection
17.#FUSES BROWNOUT                 //Reset when brownout detected
18.#FUSES NOIESO                   //Internal External Switch Over mode disabled
19.#FUSES NOFCMEN                  //Fail-safe clock monitor disabled
20.#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
21.#FUSES NODEBUG                  //No Debug mode for ICD
22.#FUSES NOWRT                    //Program memory not write protected
23.#FUSES BORV21                   //Brownout reset at 2.1V
24.#FUSES NODEBUG                  //No Debug mode for ICD
25.#FUSES NOLVP                    //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
26.#FUSES NOWRT                    //Program memory not write protected
27. 
28. 
29.#use delay(clock=4000000,RESTART_WDT)
30.//#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8,errors)
31.//#use i2c(Master,Slow,sda=PIN_C4,scl=PIN_C3,SMBUS) //,FORCE_HW ,NOFLOAT_HIGH,
32.#use i2c(Master,Slow,sda=PIN_C4,scl=PIN_C3,force_hw)
33. 
34.#use fast_io(A) // Работа с портами без переключения
35.#use fast_io(B) // каждый раз регистров TRIS
36.#use fast_io(C) //
37.#use fast_io(D) //
38. 
39.#byte PORTA = 0x05
40.#byte PORTB = 0x06
41.#byte PORTC = 0x07
42.#byte PORTD = 0x08
43.#byte PORTE = 0x09
44. 
45.#byte TRISA = 0x85
46. 
47.#byte RCSTA = 0x18
48.#bit  OERR = RCSTA.1
49.#bit  CREN = RCSTA.4
50. 
51.#byte TMR2 = 0x11
52. 
53.#bit  CTS = PORTC.0
54. 
55. 
56.#bit IrRXpin = PORTB.0   //Ir RX pin
57.#bit IrRXLEDpin = PORTA.1   //Ir RX pin
58. 
59.#define  use_portd_lcd TRUE
60.#include <LCD.C>
61. 
62. 
63.//#bit RxOverflowBit = RS232_ERRORS.1
64. 
65.#define FIFOsizemax 31
66.#define TEXTBUFFER  21
67. 
68.unsigned int16 year;
69.unsigned char mon,day,hour,min,sec,msec,week;
70.unsigned char StandBy;
71.unsigned char IrTimeOut;
72.unsigned char CustomCode1,CustomCode2,DataCode1,DataCode2,CodeCounter,IrDAclock,PrevCommand,IrRxFlag;
73.unsigned char RefreshDisplay, RefreshClock;
74.unsigned char FIFOstart,FIFOend,FIFOsize,FIFOover;
75.unsigned char FIFObuffer[FIFOsizemax];
76.unsigned int16 AdditionalInfo;
77.unsigned int16 UpdateTemperatureCount;
78. 
79.//Перечень функций
80.void main(void);
81.void TIMER0_isr(void);
82.void LCDTextOut(void);
83.void lcd_VarOut(int16 OutVar);
84.void LCDGoTo(unsigned char Pos);
85.void lcd_ZeroOut(void);
86.#separate void ShowCyrTime(void);
87.unsigned char RemoteControllRX(void);
88.void RxDataOut(void);
89.void ShowInfo(void);
90.void WriteTestTextToExtEEPROM(void);
91.void RefreshTime(void);
92.void WriteExternalFlash(void);
93.void Read10bytesFlash(void);
94.unsigned char ReadFIFO(void);
95.//void WriteFIFO(unsigned char);
96.//void InitFIFO(void);
97. 
98.//void ToggleMode(void);
99.//void ReadCurrent(void);
100.      void RefreshTemperature(void);
101.      void UpdateTemperature(void);
102.       
103.      //// My One Wire DS18S20
104.      unsigned char OneWire_reset(void);
105.      void OneWire_Write(unsigned char WData);
106.      unsigned char OneWire_Read(void);
107.       
108.      void SetTime(void);
109.       
110.      unsigned char RemoteControllRX2(void); ///TEST!!!
111.       
112.      #byte PIE1  = 0x8C
113.      #byte PIR1  = 0x0C
114.       
115.      //UART
116.      #byte TXSTA = 0x98
117.      #bit  CSRC = TXSTA.7
118.      #bit  TX9  = TXSTA.6
119.      #bit  TXEN = TXSTA.5
120.      #bit  SYNC = TXSTA.4
121.      #bit  BRGH = TXSTA.2
122.      #byte RCSTA = 0x18
123.      #bit  SPEN = RCSTA.7
124.      #bit  RX9  = RCSTA.6
125.      #byte SPBRG = 0x99
126.      #bit  TXIE  = PIE1.4
127.      #bit  RCIE  = PIE1.5
128.      #bit  TXIF  = PIR1.4
129.      #byte TXREG = 0x19
130.       
131.      //Список переменных для функции ShowInfo
132.      #define DISPLAY_COL_MAX 25
133.      unsigned int16 SI_pointer;
134.      unsigned char SI_buffer[DISPLAY_COL_MAX];
135.      unsigned int16 SI_Refresh;
136.       
137.      signed int8 CyrInTemp,CyrOutTemp;
138.       
139.      //Таблица дополнительных загружаемых символов
140.      unsigned char cgram[64] = {
141.      0x0E,0x11,0x10,0x1C,0x10,0x11,0x0E,0x00, // символ 0x00 Є
142.      0x00,0x00,0x0E,0x10,0x1c,0x10,0x0E,0x00, // символ 0x01 є
143.      0x0A,0x00,0x04,0x04,0x04,0x04,0x0E,0x00, // символ 0x02 Ї
144.      0x0A,0x00,0x0C,0x04,0x04,0x04,0x0E,0x00, // символ 0x03 ї
145.      0x02,0x05,0x02,0x00,0x00,0x00,0x00,0x00, // символ 0x04 градус
146.      0x00,0x00,0x1E,0x08,0x04,0x08,0x1E,0x00, // символ 0x05
147.      0x1f,0x00,0x1f,0x00,0x1f,0x00,0x1f,0x00, // символ 0x06
148.      0x1f,0x00,0x1f,0x00,0x1f,0x00,0x1f,0x00  // символ 0x07
149.      };
150.       
151.      void load_cgram(void)  {
152.       unsigned char x;
153.       lcd_send_byte(0,0x40);                        // вызов записи в регистры ЖКИ
154.       delay_us(45);
155.       for (x = 0; x < 64; x++)
156.         {
157.         lcd_send_byte(1,cgram[x]);                  // вызов записи данных в ЖКИ
158.         delay_us(50);
159.         }
160.       lcd_send_byte(0,0x80);                        // вызов записи в регистры ЖКИ
161.       
162.      }
163.       
164.      void putc(unsigned char bt)
165.      {
166.      //Проверяем, закончилась ли предыдущая передача
167.      while(TXIF==0); //если нет, то ждем.
168.      TXREG=bt; // Загружаем данные для передачи
169.      }
170.       
171.       
172.       
173.      #int_TIMER0
174.      void TIMER0_isr(void)
175.      {
176.      if (OERR==1) { lcd_putc("\fOver"); while(1); } //Если переполнение буфера приема - зависаем
177.      if (FIFOover==1) { lcd_putc("\fFIFO"); while(1); }
178.       
179.      mSec++;
180.      if(mSec>15)  //16
181.         { Sec++;
182.           mSec=0;
183.           if (Sec>59)
184.            { Sec=0;
185.              Min++;
186.             
187.               if (Min>59)
188.                  { Hour++;
189.                  Min=0; }
190.                if (hour>23)
191.                { day++;
192.                  hour=0;
193.                 
194.                    if ((day>28)&(mon==2))
195.                      { day=0;
196.                     mon++; }
197.                    if ((day>30)&((mon==4)&(mon==6)&(mon==4)&(mon==9)&(mon==11)))
198.                   { day=0;
199.                     mon++; }
200.                    if (day>31)
201.                   { day=0;
202.                     mon++; }
203.                    if (mon>12)
204.                   { year++;
205.                        mon=0; }
206.                  }
207.              }
208.         
209.          }
210.      if (IrDAclock<250) IrDAclock++;
211.      }
212.       
213.      void LCDTextOut(void)
214.      {
215.      //#include "codetable.h"
216.      unsigned char Ch,i,n;
217.      unsigned char buffer[TEXTBUFFER+1];
218.       
219.      for (i=0;i<TEXTBUFFER;i++) buffer[i]=0; //Инициализация буфера
220.       
221.      Ch=ReadFIFO();
222.      i=0;
223.      while (Ch!=0)               //Заполнение буфера данными из СОМ порта
224.          {
225.           buffer[i]=Ch;
226.           Ch=ReadFIFO();
227.           i++;
228.           if (i>TEXTBUFFER) break;
229.           restart_wdt();
230.         }
231.       
232.      for (n=0;n<i;n++)
233.         { if (buffer[n]>0)
234.             {/*  if(buffer[n]>122) Ch=CyrTable[Ch-123];
235.                      else
236.                                  Ch=buffer[n];
237.                if(buffer[n]==92) Ch=47;
238.              */
239.               
240.                lcd_putc(buffer[n]);
241.             }
242.       
243.           if (IrRXpin==0)          //Обрабатываем сигналы с пульта вне очереди
244.            { RemoteControllRX();}
245.           restart_wdt();
246.       
247.         } //Вывод содержимого буфера на дисплей
248.       
249.      }
250.       
251.      void lcd_VarOut(int16 OutVar)   //Вывод на ЖК числа
252.      {
253.      byte buffer[8]={0,0,0,0,0,0,0,0};
254.      unsigned char i;
255.       
256.      //sprintf(buffer,"%3.0w",OutVar);
257.      sprintf(buffer,"%lu",OutVar);
258.      i=0;
259.      while(i<8)
260.         {if (buffer[i]>32) lcd_putc(buffer[i]);
261.          i++;
262.          restart_wdt();
263.         }
264.      }
265.       
266.      void LCDGoTo(unsigned char Pos)
267.      {
268.      unsigned char x,y;
269.      if (Pos<0x40) {x=Pos; y=0;} else {x=Pos-0x40; y=1;}
270.      lcd_gotoxy(x+1,y+1);
271.      }
272.       
273.      void lcd_ZeroOut(void)
274.      { lcd_putc("0"); }
275.       
276.      #define InfoScroll 1000
277.      #define InfoScrollDate InfoScroll/3.0
278.       
279.      //#separate
280.      void ShowCurentTemperature(signed char cT)
281.      { unsigned char T;
282.        lcd_putc("єi\xBC ");
283.       
284.       
285.      //  if (cT<0)
286.      //    { lcd_putc("-"); T=0xFF-cT+1; }                  
287.      //       else
288.          T=cT;
289.        lcd_VarOut(T>>1);
290.        lcd_putc(0x04);
291.        lcd_putc(0x20); lcd_putc(0x20);
292.      //  lcd_VarOut(CyrOutTemp);
293.       
294.      }
295.       
296.       
297.      #separate void Day_Monday(void)
298.      { lcd_putc("Ёo\xBDeгi\xBBoє"); } //Понеділок
299.       
300.      #separate void Day_Tuesday(void)
301.      {lcd_putc("Biіїopoє");}
302.       
303.      #separate void Day_Wednesday(void)
304.      {lcd_putc("Cepeгa");}
305.       
306.      #separate void Day_Thursday(void)
307.      {lcd_putc("«eїіep");}
308.       
309.      #separate void Day_Friday(void)
310.      {lcd_putc("Ё'ЗїЅёеЗ");}
311.       
312.      #separate
313.      void ShowCyrTime(void)
314.      {
315.       
316.      RefreshDisplay++;
317.      if ((FIFOsize==0)&&(StandBy==1)&&(RefreshDisplay>250))
318.            {
319.               {   //Отображение времени
320.                    lcd_gotoxy(1,1);              
321.                    if (((FIFOsize==0))) { if(hour<10) lcd_ZeroOut();  lcd_VarOut(hour); }
322.                    if   (FIFOsize==0)     lcd_putc(":");
323.                    if (((FIFOsize==0))) { if(min<10) lcd_ZeroOut(); lcd_VarOut(min);    }
324.       
325.                 AdditionalInfo++;
326.                    lcd_gotoxy(7,1);
327.                 if (AdditionalInfo<(InfoScroll*(1.0/3.0)))
328.                  {//Отображение даты
329.                    if (((FIFOsize==0))&&(IrRXpin))
330.                       if (((FIFOsize==0))&&(IrRXpin)) { if(day<10) lcd_ZeroOut(); lcd_VarOut(day);    }
331.                       if (((FIFOsize==0))&&(IrRXpin)) lcd_putc(".");
332.                       if (((FIFOsize==0))&&(IrRXpin)) { if(mon<10) lcd_ZeroOut(); lcd_VarOut(mon);    }
333.                       if (((FIFOsize==0))&&(IrRXpin)) lcd_putc(".");
334.                    if (((FIFOsize==0))&&(IrRXpin)) { lcd_VarOut(year); RefreshDisplay=0; }
335.                      }
336.                    //Отображение дня недели
337.                    if ((AdditionalInfo>(InfoScroll*(1.0/3.0)))&&(AdditionalInfo<(InfoScroll*(2.0/3.0))))
338.                      {                  
339.                        if (week==2) Day_Monday(); // Понеділок
340.                        if (week==3) Day_Tuesday();
341.                        if (week==4) Day_Wednesday();
342.                        if (week==5) Day_Thursday();
343.                        if (week==6) Day_Friday();
344.                        if (week==7) lcd_putc("CyІoїa");
345.                        if (week==1) lcd_putc("Heгi»З"); //Неділя
346.       
347.      //                  lcd_putc(">"); lcd_putc(0x00); lcd_putc(0x01); lcd_putc(0x02); lcd_putc(0x03); lcd_putc(0x04);
348.       
349.                         {unsigned char fff=0;
350.                          while (fff<5)
351.                               { lcd_putc(" "); fff++;}
352.                         }  
353.                      }
354.                    //Отображение температуры
355.                     if ((AdditionalInfo>(InfoScroll*(2.0/3.0)))&&(AdditionalInfo<(InfoScroll*(3.0/3.0))))
356.                        { ShowCurentTemperature(CyrInTemp);
357.                        }
358.                   //Синхронизация часов с DS1307
359.                  if (AdditionalInfo==1) RefreshTime();
360.       
361.                  if (AdditionalInfo>InfoScroll) AdditionalInfo=0;
362.                 }
363.            }
364.      }
365.       
366.       
367.      void init_all(void)
368.      {
369.       unsigned int i;
370.       
371.      year=2008;
372.      mon=day=hour=min=sec=week=0;
373.      StandBy=1;
374.       
375.      //UpdateTemperature();
376.       
377.      SET_TRIS_A(0b10101111);
378.      SET_TRIS_C(0b10011110);
379.      SET_TRIS_D(0b00000000);
380.       
381.       
382.       
383.      lcd_init();
384.      load_cgram(); //Загрузить спец. символы
385.       
386.         setup_adc_ports(NO_ANALOGS);
387.         setup_adc(ADC_OFF);
388.         //setup_psp(PSP_DISABLED);
389.         //setup_spi(FALSE);
390.         setup_wdt(WDT_18MS|WDT_TIMES_128);
391.         setup_timer_0(RTCC_INTERNAL|RTCC_DIV_256);  
392.         setup_timer_1(T1_DISABLED);
393.         setup_timer_2(T2_DIV_BY_16,255,12);
394.         setup_comparator(NC_NC_NC_NC);
395.         setup_vref(FALSE);
396.         
397.         lcd_putc(BuildVer);
398.       
399.         delay_ms(255);
400.         delay_ms(255);
401.         delay_ms(255);
402.         delay_ms(255);
403.         delay_ms(255);
404.         delay_ms(255);
405.         delay_ms(255);
406.       
407.      //Инициализация ShowInfo
408.      for(i=0;i<DISPLAY_COL_MAX ;i++)
409.         { SI_buffer[i]=0; }
410.       
411.      RefreshClock=1; //Обновить часы побыстрее
412.       
413.       
414.         //Настройка UART
415.         SPBRG=25;   //9600=25  
416.         SYNC=0;   //TXSTA: асинхронный режим
417.         TX9=0;   //TXSTA: 8ми битный режим
418.         BRGH=1;   //TXSTA: высокоскоростной режим работы
419.         RCIE=1;  
420.         RX9=0;   //RCSTA: 8ми битный режим
421.         CREN=1;   //RCSTA: Разрешение приема
422.         SPEN=1;   //RCSTA: включение UART  
423.         TXEN=1;   //TXSTA: передача разрешенна
424.       
425.         FIFOover=FIFOsize=FIFOstart=FIFOsize=FIFOend=0;
426.       
427.         enable_interrupts(INT_TIMER0); // Прерывания от таймера0
428.       
429.       
430.      // TestDebug:
431.      IrRxFlag=0; //Сигналов с пульта не принимали
432.      lcd_putc("\f");
433.      }
434.      #separate
435.      void fn_CMD_ACCEPTED(unsigned char key)
436.      {
437.        putc(CMD_ACCEPTED);
438.        putc(key);
439.      }
440.       
441.      //Команда перевода приставки в активное состояние
442.      //#separate
443.      void fn_CMD_SET_STATE(unsigned char key)
444.      { unsigned char key2;
445.        if (key==CMD_SET_ON_STATE)
446.             { StandBy=0;}
447.        if (key==CMD_SET_OFF_STATE)
448.             { StandBy=1;}
449.        key2=ReadFIFO();
450.       
451.        fn_CMD_ACCEPTED(key);
452.         
453.        //putc(key2);
454.       
455.      }
456.      #separate
457.      void ShowError(unsigned char key)
458.      {
459.       lcd_putc("\fErr:"); lcd_VarOut(key);
460.      }
461.      #separate
462.      void DisplayClear()
463.      {lcd_putc("\f"); fn_CMD_ACCEPTED(CMD_LCD_CLEAR);}
464.       
465.      #separate
466.      void fn_CMD_SET_YEAR(void)
467.      { year=0;
468.        year=(year|((unsigned int16)(ReadFIFO())));year=year|(((unsigned int16)(ReadFIFO()))<<8);
469.        fn_CMD_ACCEPTED(CMD_SET_YEAR);
470.      }
471.       
472.      void main(void)
473.      {
474.      unsigned char key; //buffer for rx command
475.       
476.      init_all();
477.      restart_wdt();
478.      enable_interrupts(GLOBAL);      // Глобальное разрешение прерываний
479.      //DisplayClear();
480.      while(1)
481.         {
482.         
483.         //if (kbhit())   key = getch(); else key=0;
484.         if (FIFOsize>0) key=ReadFIFO(); else key=0;
485.         
486.         switch(key) {
487.           case NO_CMD        : break;
488.           case CMD_PING       : fn_CMD_ACCEPTED(CMD_PING); break; //Ping
489.           case CMD_SET_ON_STATE: putc(CMD_UNKNOWN); putc(key); StandBy=0; break;
490.           case CMD_SET_OFF_STATE:fn_CMD_SET_STATE(CMD_SET_OFF_STATE); break;
491.           case CMD_SET_LED    : ReadFIFO(); fn_CMD_ACCEPTED(CMD_SET_LED); break;
492.           case CMD_GET_ON_STATE: putc(CMD_UNKNOWN); putc(key); break;
493.           case CMD_SET_HOUR   : hour=ReadFIFO(); fn_CMD_ACCEPTED(CMD_SET_HOUR); AdditionalInfo=RefreshClock=3; break;
494.           case CMD_SET_MIN    : min=ReadFIFO();  fn_CMD_ACCEPTED(CMD_SET_MIN);  AdditionalInfo=RefreshClock=3; break;
495.           case CMD_SET_SEC    : sec=ReadFIFO();  fn_CMD_ACCEPTED(CMD_SET_SEC);  AdditionalInfo=RefreshClock=3; break;
496.           case CMD_SET_DAY    : day=ReadFIFO();  fn_CMD_ACCEPTED(CMD_SET_DAY);  AdditionalInfo=RefreshClock=3; break;
497.           case CMD_SET_MON    : mon=ReadFIFO();  fn_CMD_ACCEPTED(CMD_SET_MON);  AdditionalInfo=RefreshClock=3; break;
498.           case CMD_SET_WEEK   : week=ReadFIFO();  fn_CMD_ACCEPTED(CMD_SET_WEEK);AdditionalInfo=RefreshClock=3; break;
499.           case CMD_SET_YEAR   : fn_CMD_SET_YEAR();                              AdditionalInfo=RefreshClock=3; break;    
500.       
501.           case CMD_LCD_CLEAR  : DisplayClear(); break; //Clead Display
502.           case CMD_LCD_HOME   : LCDGoTo(0);          fn_CMD_ACCEPTED(CMD_LCD_HOME); break;
503.           case CMD_LCD_GOTO   : LCDGoTo(ReadFIFO()); fn_CMD_ACCEPTED(CMD_LCD_GOTO); break; // GoTo
504.           case CMD_LCD_TEXT   : LCDTextOut(); fn_CMD_ACCEPTED(CMD_LCD_TEXT);  StandBy=0; break; // TextOut
505.           case CMD_GET_BOARD_ID:fn_CMD_ACCEPTED(CMD_GET_BOARD_ID); putc(CMD_GET_BOARD_ID); putc(BOARD_ID_LO); putc(BOARD_ID_HI); break;  // lcd_putc("\fID version");
506.           case CMD_GET_BOARD_HW:fn_CMD_ACCEPTED(CMD_GET_BOARD_HW); putc(CMD_GET_BOARD_HW); putc(0x01); putc(0x00); break;                // lcd_putc("\fHW version");
507.           case CMD_GET_BOARD_SW:fn_CMD_ACCEPTED(CMD_GET_BOARD_SW); putc(CMD_GET_BOARD_SW); putc(0x02); putc(0x00); break;                // lcd_putc("\fSW version");
508.           case CMD_GET_BOARD_INFO:fn_CMD_ACCEPTED(CMD_GET_BOARD_INFO); putc(CMD_GET_BOARD_INFO); putc(0x33); putc(0x34); putc(0x35); putc(0x00); break;
509.       
510.           case CMD_W_EXT_FLASH: WriteExternalFlash(); fn_CMD_ACCEPTED(CMD_W_EXT_FLASH);  break;
511.      //     case CMD_R_EXT_FLASH: Read10bytesFlash(); break;
512.         
513.       
514.            default             : putc(CMD_UNKNOWN); putc(key); ShowError(key); break; //Unknown command
515.                   }        
516.       
517.      ///// WriteExternalFlash(); ///***********
518.         restart_wdt();
519.       
520.       
521.       
522.      //Если была команда установки года, то сохраним это все в RTC
523.        if(key==CMD_SET_SEC) SetTime();
524.       
525.         if (IrRXpin==0)
526.            { RemoteControllRX(); }  
527.       
528.         if ((key==NO_CMD)&&(StandBy==1))
529.            { UpdateTemperature(); //Функция считывания значения температуры
530.              ShowInfo();          //Вывод на дисплей времени, даты и др.
531.              ShowCyrTime();  
532.              restart_wdt();
533.            }
534.       
535.         if ((IrRxFlag==1)&&(FIFOsize==0)&&(key==NO_CMD))
536.            { RxDataOut();  //Отправка в порт принятой команды с ИК пульта ДУ
537.              IrRxFlag=0;
538.              }      
539.       
540.      /*   if ((IrRxFlag==1)&&(FIFOsize==0)) //???
541.            { RxDataOut();
542.              IrRxFlag=0;
543.              }      
544.      */
545.       
546.       
547.         }
548.      }
549.       
550.      #define Min0RxBitTime 58
551.      #define Max0RxBitTime 100
552.      #define Min1RxBitTime 116
553.      #define Max1RxBitTime 174
554.       
555.      unsigned char IrRXbyteNEC(unsigned char RxByte)
556.      {
557.      unsigned char IndexByte,BitTime,BitMask,RxByte2;
558.      CTS=0;
559.      IndexByte=0;
560.      RxByte2=0;
561.      //RxByte=10;
562.      while(IndexByte<8)
563.        { while((IrRXpin==0)&&(IrTimeOut==0)) restart_wdt(); // начало синхроимпульса
564.         while((IrRXpin==1)&&(IrTimeOut==0)) restart_wdt();  // конец синхроимпульса
565.          while((IrRXpin==0)&&(IrTimeOut==0)) restart_wdt();  // начало следующего бита
566.          BitTime=TMR2;
567.          if (IrTimeOut>1) break;
568.             TMR2=IrTimeOut=0;
569.          if ((BitTime<Min0RxBitTime)|(BitTime>Max1RxBitTime)) { IrTimeOut=1; break; }
570.          if (BitTime<Max0RxBitTime) BitMask=0;
571.          if (BitTime>Min1RxBitTime)
572.              { BitMask=1;
573.                BitMask=BitMask<<IndexByte;
574.               RxByte2|=BitMask;
575.              }
576.          IndexByte++;
577.        }
578.       
579.      if (CodeCounter==1) CustomCode1=RxByte2;
580.      if (CodeCounter==2) CustomCode2=RxByte2;
581.      if (CodeCounter==3) DataCode1=RxByte2;
582.      if (CodeCounter==4) DataCode2=RxByte2;
583.      RxByte=RxByte2;
584.       
585.      if (IrTimeOut==0)
586.        { return 1; }
587.          else
588.        { return 0; }
589.       
590.      }
591.       
592.      unsigned char RemoteControllRX2(void)
593.      {
594.       
595.      putc(CMD_ACCEPTED);   //Test UART transmit
596.      putc(CMD_ACCEPTED);
597.      putc(CMD_ACCEPTED);
598.      putc(CMD_ACCEPTED);
599.       
600.       
601.      CustomCode1=0x02;
602.      CustomCode2=0xFD;
603.      DataCode1=0x01;
604.      DataCode2=0xFE;
605.       
606.      IrRxFlag=1;
607.      IrRXLEDpin=1;
608.      return 1;
609.       
610.      }
611.       
612.       
613.      unsigned char RemoteControllRX(void)
614.      {
615.      unsigned char bitIndex;
616.      //Готовим буфер для приема
617.      //IrRXLEDpin=1;
618.      if (IrRxFlag==1) goto RxOK; //Если уже есть принятая, но неотправленная команда, то выходим
619.      CustomCode1=CustomCode2=DataCode1=DataCode2=bitIndex=0;
620.      //lcd_putc("\fIrDA");
621.       
622.      //Готовим таймер1
623.      setup_timer_2(T2_DIV_BY_4,255,1); //переполнение каждые 1024 мкс
624.      //setup_timer_2(T2_DIV_BY_16,255,1);  //переполнение каждые 4096 мкс
625.      enable_interrupts(INT_TIMER2);
626.      //Ждем окончания стартового бита. Бит 1.
627.      TMR2=IrTimeOut=0;
628.      //while((IrRXpin==0)&(IrTimeOut<10));
629.      while(1)
630.         { if (IrRXpin!=0) break;
631.            if (IrTimeOut>10) break;
632.           restart_wdt();
633.         }
634.      if (IrTimeOut>10) GoTo RxTimeOut;
635.       
636.      //Пауза на 4 мс
637.      TMR2=IrTimeOut=0;
638.      while(IrTimeOut<3) restart_wdt();
639.       
640.      setup_timer_2(T2_DIV_BY_16,255,1);  //переполнение каждые 4096 мкс
641.       
642.      //Ждем появления первого байта
643.      TMR2=IrTimeOut=0;
644.      while((IrRXpin==1)&(IrTimeOut==0)) restart_wdt();
645.      if (IrTimeOut>0) GoTo RxTimeOut;
646.      //Прием байта Custom code
647.      TMR2=IrTimeOut=0;
648.      CodeCounter=1;
649.      if (!IrRXbyteNEC(CustomCode1)) GoTo RxTimeOut;
650.      CodeCounter=2;
651.      if (!IrRXbyteNEC(CustomCode2)) GoTo RxTimeOut;
652.      CodeCounter=3;
653.      if (!IrRXbyteNEC(DataCode1))   GoTo RxTimeOut;
654.      CodeCounter=4;
655.      if (!IrRXbyteNEC(DataCode2))   GoTo RxTimeOut;
656.       
657.      disable_interrupts(INT_TIMER2);
658.      //Функция отладки. Логический анализатор
659.       
660.      GoTo RxOK;
661.       
662.       
663.      RxTimeOut:; //Метка. Сюда переходим, если были ошибки приема
664.      IrRxFlag=0;
665.      IrRXLEDpin=0;
666.      return 0;
667.       
668.      goto DataOut;
669.       
670.      RxOK:;
671.      IrRxFlag=1;
672.      IrRXLEDpin=1;
673.      return 1;
674.       
675.      DataOut:;   //Вывод данных на дисплей
676.      }
677.       
678.       
679.      void RxDataOut(void)
680.      {
681.      //lcd_putc("\f");
682.      //Проверяем код устройства:
683.      if ((CustomCode1==0x02)||(CustomCode2==0xFD)||(CustomCode2==0x03)||(CustomCode2==0xFC))
684.         { //Проверяем принятый байт команды на правильность
685.           if (DataCode1==(255-DataCode2))
686.               { //Если все совпало, то выполняем антидребезг
687.                 if((PrevCommand!=DataCode1)||(IrDAclock>6)) //5
688.                  { putc(CMD_IR_CODE);  //Если следующая команда другая или прошло больше 1 сек,то передаем команду
689.                     if((CustomCode1==0x02)||(CustomCode2==0xFD)) putc(DataCode1); // Мой пульт использует два кода оборудования
690.                     if((CustomCode1==0x03)||(CustomCode2==0xFC)) putc(DataCode1+0xE0); // Для дополнительного кода +0xE0
691.                    IrDAclock=0;        //
692.                    PrevCommand=DataCode1;
693.                      IrRXLEDpin=0;
694.                  }
695.               }  
696.         }
697.       
698.      }
699.       
700.      #int_TIMER2
701.      void TIMER2_isr()
702.      {
703.      IrTimeOut++;//Флаг переполнения таймера
704.      }
705.       
706.       
707.      //Появился байт в буфере приема
708.      #byte RCREG = 0x1A
709.       
710.      //Считывание байта из буфера приема в FIFO буфер
711.      #int_RDA
712.      void  RDA_isr(void)
713.      {
714.      unsigned char RxByte;
715.      RxByte=RCREG;
716.      if (FIFOsize<FIFOsizemax) // Проверяем, есть ли место
717.              { FIFObuffer[FIFOend]=RxByte; //Записываем в буфер значение
718.              FIFOend++;        // Увеличиваем показания счетчика позиции (указатель)
719.              FIFOsize++;       // Увеличиваем значение размера буфера
720.              if (FIFOend>=FIFOsizemax) //Проверяем выход за конец буфера
721.               { FIFOend=0;}   // и устанавливаем указатель в начало
722.              restart_wdt();
723.       
724.            } else FIFOover=1;
725.       
726.      }
727.       
728.       
729.      //Чтение из буфера приема
730.      unsigned char ReadFIFO(void)
731.      { unsigned char FIFObyte;
732.        while(FIFOsize==0) restart_wdt(); //Ожидание получения следующего байта
733.         if (FIFOsize>0) // Если размер буфера больше нуля
734.            { FIFObyte=FIFObuffer[FIFOstart]; // Считываем байт из буфера
735.               FIFOsize--;                 // Количество байт в буфере -1
736.              FIFOstart++;                 // Указатель на следующий байт
737.              if (FIFOstart>=FIFOsizemax)     // Если дошли до границы буфера
738.                  {FIFOstart=0;}            // переходим в начало
739.              restart_wdt();
740.            }
741.      return FIFObyte;
742.      }
743.       
744.       
745.      //Функция для вывода текстовой информации из внешней памяти во второй строке дисплея
746.      void ShowInfo(void)
747.      {
748.      unsigned char i;
749.       
750.      if (SI_Refresh<8192) GoTo SI_END;
751.      SI_Refresh=0;
752.       
753.      disable_interrupts(GLOBAL);
754.       
755.      if (SI_buffer[0]==0x00)
756.        { //Буфер пуст. Начинаем загрузку текста с начала
757.         SI_pointer=0x00;
758.         //Указываем начальный адресс для чтения данных
759.        }
760.      //if (SI_pointer!=0x00)
761.        { // Если указатель указывает не на адресс 0
762.          // то следует сместить данные на 1 байт
763.         i=0;
764.         while(i<(DISPLAY_COL_MAX-1))
765.            { SI_buffer[i]=SI_buffer[i+1];
766.                i++;
767.            }
768.         SI_buffer[DISPLAY_COL_MAX-1]=0x00;
769.        }
770.      restart_wdt();
771.       
772.      //Ищем первую свободную ячейку в буфере
773.      i=0;
774.      while((SI_buffer[i]!=0x00)&&(i<DISPLAY_COL_MAX)) i++;
775.       
776.       
777.       
778.      if (i<(DISPLAY_COL_MAX-5))  //Делаем чтение блоками
779.        {                         //по 5 байт
780.      delay_us(90);
781.          i2c_start();         // Restart
782.          i2c_write(0xA7);     // Адресс устройства
783.       
784.      while(i<DISPLAY_COL_MAX)
785.         {// Загружаем данные в буфер до его заполнения
786.      delay_us(255);
787.         restart_wdt();    
788.      if (i<DISPLAY_COL_MAX-1)
789.          SI_buffer[i] = i2c_read(1);
790.        else
791.          SI_buffer[i] = i2c_read(0);
792.         
793.         if (SI_buffer[i]==0x00)
794.                      { // Найден маркер конца сообщения.
795.                // указываем адресс начала
796.                i2c_read(0);     // Даем сигнал окончания чтения
797.                i2c_stop();      // Посылаем сигнал СТОП
798.                i2c_start();     // Старт
799.                i2c_write(0xA6); //Режим записи
800.                i2c_write(0x00); // Адресс ячейки
801.                i2c_write(0x00); // Адресс ячейки
802.                i2c_start();     // Старт
803.                i2c_write(0xA7); //Режим чтения  
804.       
805.                if (i<DISPLAY_COL_MAX-1)
806.                    SI_buffer[i] = i2c_read(1);
807.                  else
808.                    SI_buffer[i] = i2c_read(0);
809.       
810.                SI_pointer=0;
811.                      }
812.       
813.       
814.         i++;
815.          SI_pointer++;
816.         }
817.       
818.          i2c_stop();    
819.          i2c_stop();    
820.        }
821.       
822.      i=0;
823.      lcd_gotoxy(1,2);
824.      while(i<(DISPLAY_COL_MAX-5))
825.         { //Вывожу текст на экран
826.          if (SI_buffer[i]>0) lcd_putc(SI_buffer[i]);
827.           i++;
828.          restart_wdt();
829.         }
830.      enable_interrupts(GLOBAL);
831.      SI_END:;
832.      SI_Refresh++;
833.      }
834.       
835.       
836.       
837.      //Преобразования из двоичной системы в двоично-десятичную
838.      unsigned char rtf_format(unsigned char rtc_data)
839.      {
840.      unsigned char buf[2],rtc_res_data;
841.       
842.      sprintf(buf,"%2d",rtc_data);
843.      if (buf[0]==0x20) buf[0]=48;
844.      rtc_res_data=(buf[0]-48)<<4;
845.      rtc_res_data+=(buf[1]-48);
846.       
847.      return rtc_res_data;
848.      }
849.       
850.      //Функция установки текущего времени в часах реального времени DS1307
851.      void SetTime(void)
852.      {
853.      unsigned char rtc_data;
854.       
855.          i2c_start();     // Старт
856.          i2c_write(0xD0); // DS1307.Запись
857.          i2c_write(0);    // Начинаем с минут
858.       
859.      //Подготовка значения секунд
860.          rtc_data=rtf_format(sec);
861.          i2c_write(rtc_data);
862.          rtc_data=rtf_format(min);
863.          i2c_write(rtc_data);
864.          rtc_data=rtf_format(hour);
865.          i2c_write(rtc_data);
866.       
867.      /* //Тут мы пропускаем регист дня недели
868.          i2c_start();     // Старт
869.          i2c_write(0xD0); // DS1307.Запись
870.          i2c_write(0x04);    // 4я ячейка. */
871.         
872.          i2c_write(week); // День недели
873.          rtc_data=rtf_format(day);
874.          i2c_write(rtc_data);
875.          rtc_data=rtf_format(mon);
876.          i2c_write(rtc_data);
877.          rtc_data=rtf_format((unsigned int16)(year-2000));
878.          i2c_write(rtc_data);
879.          rtc_data=0b00000000; //Байт настроек доп. выхода.
880.          i2c_write(rtc_data);
881.       
882.       
883.          i2c_stop();
884.          restart_wdt();
885.      }
886.       
887.       
888.       
889.      //Функция чтения текущего времени из часов реального времени DS1307
890.      void RefreshTime(void)
891.      {
892.      unsigned char rtc_day,rtc_mon,rtc_year,rtc_hour,rtc_min,rtc_sec;
893.       
894.      if (RefreshClock!=1) GoTo NoRTCfounded; // Обновляем показания очень редко!
895.       
896.          i2c_start();     // Старт
897.          i2c_write(0xD0); // Адресс устройства
898.          i2c_write(0);   // Адресс ячейки
899.       
900.          i2c_start();         // Restart
901.          i2c_write(0xD1);     // Адресс устройства
902.       
903.          rtc_sec =i2c_read(1)&0b01111111;  // Чтение секунд
904.          rtc_min =i2c_read(1)&0b01111111;  
905.          rtc_hour=i2c_read(1)&0b00111111;  
906.          week=i2c_read(1)    &0b00000111;  
907.          rtc_day=i2c_read(1) &0b00111111;  
908.          rtc_mon=i2c_read(1) &0b00011111;  
909.          rtc_year=i2c_read(0);  
910.       
911.          i2c_stop();    
912.       
913.          restart_wdt();
914.       
915.      if (rtc_sec==0x7F) GoTo NoRTCfounded;
916.       
917.      //sec =(rtc_sec &0b00001111+((rtc_sec &0b01110000)>>4)*0x0A);
918.      sec =rtc_sec & 0b00001111;
919.      sec =(rtc_sec>>4)*0x0A+sec;
920.       
921.       
922.      //min =(rtc_min &0b00001111+((rtc_min &0b01110000)>>4)*0x0A);
923.      min =rtc_min &0b00001111;
924.      min =(rtc_min>>4)*0x0A + min;
925.      //hour=(rtc_hour&0b00001111+((rtc_hour&0b00110000)>>4)*0x0A);
926.      hour=rtc_hour&0b00001111;
927.      hour=(rtc_hour>>4)*0x0A+hour;
928.       
929.      //day =(((rtc_day &0b00110000)>>4)*0x0A+rtc_day &0b00001111);
930.      day = rtc_day &0b00001111;
931.      day =(rtc_day>>4)*0x0A + day;
932.       
933.      //mon =(rtc_mon &0b00001111+((rtc_mon &0b00010000)>>4)*0x0A);
934.      mon =rtc_mon &0b00001111;
935.      mon =(rtc_mon>>4)*0x0A + mon;
936.       
937.      //year=rtc_year&0b00001111 +((rtc_year&0b11110000)>>4)*0x0A;
938.      year=rtc_year&0b00001111;
939.      year=(rtc_year>>4)*0x0A+year;
940.      year+=2000;
941.      NoRTCfounded:;
942.      RefreshClock++;
943.      if (RefreshClock>5) RefreshClock=0;
944.      }
945.       
946.      void WriteExternalFlash(void)
947.      {
948.      unsigned char S;
949.      unsigned int16 adr;
950.      if (ReadFIFO()==0x31)
951.         {if (ReadFIFO()==0x39) //Защита от случайной записи
952.            {
953.              i2c_start();     // Старт
954.              i2c_write(0xA6); // Адресс устройства
955.              delay_us(50);
956.              i2c_write(0);    // Адресс ячейки
957.              i2c_write(0);    // Адресс ячейки
958.       
959.              adr=0;  
960.             
961.              do  { i2c_start();     // Старт
962.       delay_us(100);
963.                    i2c_write(0xA6); // Адресс устройства
964.       delay_us(100);
965.                    //i2c_write((adr&0b1111111100000000)>>8);    // Адресс ячейки
966.                    i2c_write(adr>>8);    // Адресс ячейки  
967.       delay_us(100);
968.                    i2c_write(adr);    // Адресс ячейки
969.                    //i2c_write(adr &0b0000000011111111);    // Адресс ячейки
970.       
971.                    S=ReadFIFO();
972.                    i2c_write(S);
973.       
974.                                if (S==0x00) i2c_write(S); //Записываем подряд два нуля.
975.       delay_us(100);
976.                    i2c_stop();
977.                    delay_ms(6);
978.                    restart_wdt();
979.                    adr++;
980.                 //   if (S==0x40) break;
981.                  } while ((S!=0x00)&&(S!=0xFF));
982.            }
983.              else
984.              putc(CMD_UNKNOWN);
985.         }
986.          else
987.          putc(CMD_UNKNOWN);
988.      }
989.       
990.      void Read10bytesFlash(void)
991.      {
992.      unsigned char i,sec;
993.       
994.          i2c_start();     // Старт
995.          i2c_write(0xA7); // Адресс устройства
996.          i=1;
997.              while(i<10)
998.                      {if (i<9)
999.          sec = i2c_read(1);
1000.       else
1001.         sec = i2c_read(0);
1002.              putc(sec);
1003.                      i++;
1004.                     restart_wdt();
1005.                     }
1006.      
1007.         i2c_stop();    
1008.     }
1009.      
1010.      
1011.      
1012.     //******
1013.      
1014.     #bit    DS1821_PIN = PORTA.4
1015.     #define DS1821_PIN_INPUT  TRISA|=0b00010000;
1016.     #define DS1821_PIN_OUTPUT TRISA&=0b11101111;
1017.      
1018.     //Команды OneWire интерфейса
1019.     #define SEARCH_ROM 0xF0
1020.     #define READ_ROM   0x33
1021.     #define MATCH_ROM  0x55
1022.     #define SKIP_ROM   0xCC
1023.      
1024.     //Команды DS1821
1025.     #define DS1821_Start_Convert_T   0xEE
1026.     #define DS1821_Stop_Convert_T    0x22
1027.     #define DS1821_Read_Temperature  0xAA
1028.      
1029.     //Команды DS1820
1030.     #define DS1820_Start_Convert_T   0x44
1031.     #define DS1820_Read_Scratchpad   0xBE
1032.      
1033.     //=== Reset ===
1034.     unsigned char OneWire_reset(void)
1035.     {
1036.     int1 DeviceOK;
1037.     unsigned char wait;
1038.      
1039.     //Выдаем "0" в линию
1040.     DS1821_PIN=0;
1041.     DS1821_PIN_OUTPUT
1042.      
1043.     //Пауза на 480 мкс
1044.     Delay_us(250);
1045.     Delay_us(230);
1046.      
1047.     //Отпускаем линию на 15 мкс
1048.     DS1821_PIN_INPUT
1049.     Delay_us(15);
1050.      
1051.     //Ожидаем импульс подтверждения от ведомых устройств 60 мкс
1052.     wait=DeviceOK=0;
1053.     while(wait<37)
1054.             { wait++;
1055.          if (DS1821_PIN==0) { DeviceOK=1; }
1056.         }
1057.     //lcd_VarOut(PORTA);
1058.     restart_wdt();
1059.     return DeviceOK;
1060.     }
1061.     //#define nop #asm nop; #endasm
1062.     //Функция отправки лог. 0 в линию
1063.     void OneWire_Send0(void)
1064.     { // Посылаем 0 в течении 80 мкс
1065.       DS1821_PIN_OUTPUT
1066.       delay_us(80);
1067.       DS1821_PIN_INPUT
1068.     }
1069.     //Функция отправки лог. 1 в линию
1070.     void OneWire_Send1(void)
1071.     { // Посылаем 0 в течении 1 мкс
1072.       DS1821_PIN_OUTPUT //(начало тайм-слота)
1073.       delay_us(1);
1074.       DS1821_PIN_INPUT
1075.       // Посылаем 0 в течении 80 мкс
1076.       delay_us(80);
1077.     }
1078.      
1079.     void OneWire_Write(unsigned char WData)
1080.     {
1081.     unsigned char i;
1082.     i=0;
1083.     while(i<8)
1084.             { if ((WData&0b00000001)==1)
1085.             OneWire_Send1();
1086.                   else
1087.             OneWire_Send0();    
1088.          WData=WData>>1;
1089.          i++;
1090.             }
1091.     restart_wdt();
1092.     }
1093.     //Чтение данных из шины. Таймслот = 60...120 мкс
1094.     unsigned char OneWire_Read(void)
1095.     {
1096.     unsigned char i,RData;
1097.     #locate Dbit = 0x7F
1098.     //int1 Dbit;
1099.     i=0;
1100.     while(i<8)
1101.             {//Принятый бит
1102.          Dbit=1;
1103.          //Смещаем принятые биты
1104.          RData=RData>>1;
1105.          
1106.          //Посылаем тактовый импульс
1107.          DS1821_PIN_OUTPUT //(начало тайм-слота)
1108.          delay_us(1);
1109.          DS1821_PIN_INPUT
1110.          delay_us(4);
1111.      
1112.          if (DS1821_PIN==0) Dbit=0; //15 мкс
1113.          if (DS1821_PIN==0) Dbit=0; //30 мкс
1114.          if (DS1821_PIN==0) Dbit=0; //45
1115.          if (DS1821_PIN==0) Dbit=0; //60
1116.          if (DS1821_PIN==0) Dbit=0; //75
1117.          if (DS1821_PIN==0) Dbit=0; //90
1118.          if (DS1821_PIN==0) Dbit=0; //105
1119.          if (DS1821_PIN==0) Dbit=0; //120
1120.          if (DS1821_PIN==0) Dbit=0; //135
1121.          if (DS1821_PIN==0) Dbit=0; //150
1122.          if (DS1821_PIN==0) Dbit=0;
1123.          if (DS1821_PIN==0) Dbit=0;
1124.          if (DS1821_PIN==0) Dbit=0;
1125.          if (DS1821_PIN==0) Dbit=0;
1126.          if (DS1821_PIN==0) Dbit=0;
1127.      
1128.          if (Dbit==1) RData|=0b10000000;
1129.          
1130.          //Пауза в 1 мкс
1131.          delay_us(15);
1132.          i++;
1133.             }
1134.     restart_wdt();
1135.     return RData;
1136.     }
1137.      
1138.     void UpdateTemperature(void)
1139.     {
1140.      
1141.     if (UpdateTemperatureCount!=0) GoTo EndUT;
1142.      
1143.      disable_interrupts(GLOBAL);
1144.     if (OneWire_reset()==1)
1145.         { // Есть сигнал ответа от ведомого
1146.           // продолжим....
1147.          delay_us(1);
1148.          //Обращаемся ко всем (или единственному на проводе)
1149.      
1150.          //Даем команду чтения температуры
1151.          OneWire_Write(SKIP_ROM);
1152.          delay_us(100);
1153.          //OneWire_Write(DS1821_Read_Temperature);  //DS1821
1154.          OneWire_Write(DS1820_Read_Scratchpad); //DS18S20
1155.      
1156.          delay_us(100);
1157.          CyrInTemp=OneWire_Read();    
1158.      
1159.       // CyrInTemp=OneWire_Read()<<8+CyrInTemp;
1160.      
1161.          //Даем команду на запуск преобразования температуры
1162.          OneWire_reset();
1163.          OneWire_Write(SKIP_ROM);
1164.          delay_us(1);
1165.          //OneWire_Write(Start_Convert_T);
1166.          OneWire_Write(DS1820_Start_Convert_T); //DS18S20
1167.      
1168.        
1169.             }
1170.     enable_interrupts(GLOBAL);
1171.      
1172.     EndUT:;
1173.     UpdateTemperatureCount++;
1174.     }

Опубліковано

Оновлено 30.11.2023


Serhii K Home Page (c) 2003-2023
(SKNewVersion)