Для такой схемы подходит включение транзистора, показанное на рис.3. Когда ключ открыт, транзистор находится в закрытом состоянии и на входы RESET AVR и RST LCD-дисплея поступает сигнал логической единицы. Когда ключ замыкается, транзистор открывается и на входы сброса устройств поступает сигнал логического нуля.
Рис.3 Схема формирования сигнала сброса
2.4 Схемы входных и выходных устройств
Входным устройством в нашем проекте является микросхема обеспечения связи по протоколу передачи данных RS-485 МАХ 485 со следующими электрическими характеристиками:
Из этих параметров видно, что микросхема МАХ485 согласуется с микроконтроллером ATmegal6.
Рис. 4 Подключение микросхемы MAX4S5
Выходное устройство жидкокристаллический графический дисплей BG12864D фирмы Bolymin со встроенным контроллером Т6963С. Этот дисплей обладает следующими характеристиками:
• Механические характеристики
• Назначение выводов
В соответствии с этими параметрами схема подключения LCD-дисплея к микроконтроллеру будет следующей:
2.5 Схема стабилизатора напряжения
В качестве стабилизатора напряжения в нашем устройстве используется импульсный понижающий стабилизатор LM2574, который обладает следующими характеристиками:
• входное напряжение - до 60 V {для HV версий)
• выходное напряжение - 3.3 V, 5 V, 12 V, 15V
• выходной ток - 0.5 А
Схема включения стабилизатора для преобразования +10 V - +5 V приведена на рис.6:
Рис. 6 (Схема стабилизатора напряжения
3. Проектирование программного обеспечения микроконтроллера
3.1 Проектирование функции инициализации микроконтроллера
Процедура инициализации микроконтроллера должна состоять из процедур или операторов инициализации всех узлов самого микроконтроллера и всех периферийных устройств, и установить все начальные значения для их регистров. Таким образом, мы должны проинициализировать следующие узлы устройства - порт А, порт С, УСАПП, таймер 0 и LCD-дисплей.
Порты А и С в начале работы устройства работают только на вывод данных, поэтому при их настройке необходимо в соответствующие регистры DDRx записать значение 0, тем самым настроив все их выводы на передачу данных. Для этого используются две процедуры;
void InitPortAWrite(void){
DDRA = Oxff; }
void InitPortCWrite(void){ DDRC = Oxff; PORTC = 0x30;
Инициализация таймера О проходит по следующему алгоритму - устанавливается делитель частоты на 1024 записью значения 5 в регистр TCCRO. Затем разрешается прерывание этого таймера и устанавливается его начальное значение:
void InitTimer(void)
i
_disable_interrupt() ;
TCCRO = 5;// установить делитель частоты 1024
TIMSK |= (1 « TOIEO); // разрешить прерывания таймера
TCNTO = TmrO_Reload;
enable_interrupt{);
]
Инициализация УСАПП работает следующим образом - в регистр
UBRR записывается значение, которое соответствует заданной скорости передачи данных для соответствующей частоты работы микроконтроллера.
УСАПП и параметры кадра данных. Кроме этого, т.к. прием и обработка данных в программе происходит через кольцевой буфер, то в процедуре инициализации необходимо провести начальные установки для головы и хвост буфера - обнулить их.
void USART_Init( unsigned int baudrate )
unsigned char x;
UBRROH = (unsigned char) (baudrate»8) ; UBRROL = (unsigned char) baudrate;
UCSRB = (USARTJRxHead = x;
3.2 Проектирование процедур обработки прерываний
В процессе работы нашего устройства могут возникнуть два прерывания - от таймера 0 и от УСАПП. Прерывание от таймера О обрабатывается очень просто: перезагружается начальное значение и флаг его срабатывания устанавливается в 1.
pragma vector=TIMERO_OVF_vect
interrupt void TIMERO_OVF_interrupt(void)
{
TCNT0=TmrO_Reload; TmrOFlag = 1;
}
Прерывание от УСАПП говорит о том, что прием пакета данных был закончен и принят в буферный регистр UDR. Обработчик этого прерывания должен принять эти данные и поместить в кольцевой буфер. Для этого должен быть рассчитан новый индекс буфера (указатель головы) и если этот индекс вдруг стал равен указателю хвоста, это говорит о том, что произошла ошибка и буфер приемника переполнился.
^pragma vector=USART_RXC__vect
^interrupt void USART_RX_interrupt{ void )
unsigned char data; unsigned char tmphead;
data = UDR;
tmphead = ( USART_RxHead + 1 );
USART_RxHead = tmphead; /* Сохранить новый индекс V
if < tmphead == USART_RxTail )
(
/* Ошибка! Буффер приемника переполнен */
)
USART_RxBuf[tmphead] = data; /* Сохранить полученные данные в буффере */
3.3 Проектирование процедур ввода информации
Ввод информации в разрабатываемое устройство осуществляется через УСАПП по протоколу RS-4 85. Как уже отмечалось, прием данных в программе происходит по прерыванию от УСАПП, обработчик которого помещает принятый байт в Оуфер приемника. В главной программе, для того, чтобы можно было анализировать этот буфер и читать данные уже непосредственно из него, необходима процедура, которая будет доставать данные из буфера таким образом, чтобы первыми поступали байты, попавшие в буфер раньше всех. Это делает процедура USART_Receive(), которая сначала ждет поступления данных в буфер, а затем по одному байту достает их оттуда.
BYTE USART_Receive( void )
1
unsigned char tmptail;
while ( USARTJixHead == USART_RxTail )
;
tmptail = USART_RxTail + 1; USART_RxTail = tmptail; return USART_RxBuf[tmptail];
f
3.4 Проектирование процедур вывода информации
Вывод информации в нашем устройстве осуществляется на LCD-дисплей. Основной процедурой, которая отображает строки поступивших данных на дисплее - это процедура AutoWriteMode(), которая по сути управляет дисплеем, выводя на него последовательно символы, хранящиеся в глобальном массиве OutString[], в режиме автозаписи, При этом нам необходимо только менять адрес позиции, в которую выводятся данные.
WORD AutoWriteMode(WORD Address, BYTE NumBytes)
SetAddressPointer(Address); SendCommanct{SET_DATA_AUTO_HRITE_COMMAND);
forfint i = 0; i < NumBytes; i++) {
AutoWrite(OutString[i]);
Address++; }
SendCommand(AUTO_RESET_COMMAND); return Address; }
3.5 Проектирование процедур управления периферийными устройствами
Все процедуры управления LCD-дисплеем осуществляются согласно системе команд встроенного контроллера Т6963:
3.6 Проектирование процедуры main()
Процедура main{) работает следующим образом после инициализации все узлов AVR и периферийных устройств, разрешается выполнение всех прерываний. После этого программа ждет срабатывания таймера, который настроен таким образом, что он немного чаще, чем может происходить прерывание от УСАПП. Сигналом того, что таймер 0 сработал служит факт установки глобальной переменной TmrOFlag в 1, что делается обработчиком прерываний таймера.
Затем, все время, пока кольцевой буфер не будет пуст, происходит считывание данных из него. Считанный байт помещается в строку-массив OutString[], и увеличивается счетчик принятых байт.
После этого проверяется, а не был ли последний принятый из буфера байт признаком окончания строки. Если да, то в режиме автозаписи эта строка выводится на дисплей (за исключением последнего символа конца строки). После этого строка обнуляется и счетчик принятых байт устанавливается в ноль.
В любом случае происходит сброс флага таймера в ноль и происходит ожидание следующего срабатывания таймера.
4. Листинг программы
Файл макроопределений my_header.h:
^define BYTE unsigned char ttdefine WORD unsigned int
ttdefine READ_STATUS_COMMAND 0x39
ttdefine DATA_WRITE_COMMAND 0x32
tfdefine COMMANDjmTE_COMMAND ОхЗА
// Установка регистров
^define SET_CURSOR_COMMAKD 0x21
tfdefine SET_OFFSET_COMMAND 0x22
#define SET_ADDRESS_COMMAND 0x24
// Установка контрольного слова
#define SET_TEXT_HOME_ADDRESS_COMMAND 0x^0
fldefine SET_TEXT_AREA_COMMAHD0x41
#define SET_GR№HIC_HOME_ADDRESS_CO№1AND 0x42
#define SET_GRAPHIC_AREA_CCMMAND0x43
// Константы установки режима
^define OR_MODE0x80
tfdefine EXOR_MODE0x81
^define ANDJMODE0x83
#define TEXT_ATTRIBUTE_MODE0x84
^define INTERNAL_CG_ROM_MODE 0x80
tfdefine EXTERNAL_CG_RAM__MODE 0x88
// Константы режима дисплея
#define DISPLAY_OFF0x90
^define CURSOR_ON_BLIHK_OFF0x92
^define CURSOR_ON_BLINK_OK0x93
#define TEXT_ON_GRAPHIC_OFF0x94
#define TEXT__OFF_GRAPHIC_ON0x98
^define TEXT_ON_GRAPHIC_OnOX9C
// Размер курсора
#define ONE_LINE OxAO
tfdefine TWO_LINE OxAl
^define THREE_LINEOxA2
ttdefine FOUR_LINE ОхАЗ
^define FIVE_LINE OxA4
^define SIX_LINE OxA5
^define SEVEN_LINEOxA6
^define EIGHT_LINEOxA7
// Автоматическое чтение/данных
tfdefine SET_DATA_AUTO_WRITE_COMMAND OxBO
^define SET_DATA_AUTO_READ_COMMAND OxBl
^define AUTO_RESET_COMMANDOxB2
//
#define SCREEN_PEEK_CCMMANDOxEO
#define SCREEN_COPY_CC»1MANDOxE8
// Установка/сброс Оитов
tfdefine SET_BIT OxFO
^define RESET_BIT OxF8
^define BIT_0 OxFO
#define BIT_1 OxFl
ttdefine BIT_2 OxF2
^define BIT_3 OxF3
idefine BIT_4 OxF4
#define BIT_5 OxFS
^define BIT_6 OxF6
^define BIT_7OxF7
Файл главкой программы kurs.c;
/* Includes */ ^include <iom!28.h> ^include <ina90.h>
Sinclude "my_header.h"
^define USART_RX_BUFFER_SI2E 128
itdefine TmrOReload 4
static unsigned char TmrOFlag;
Static unsigned char USART_RxBuf[USART_RX_BUFFER_SIZE];
static volatile unsigned char USART_RxHead; static volatile unsigned char USART_RxTail;
static BYTE OutString[128];
// Процедуры инициализации устройств
void InitAVR(void);
void USART_Init( unsigned int baudrate );
void InitLCD(void);
void InitTimer(void);
void InitPortARead(void);
void InitPortAWrite(void)?
void InitPortCWrite(void);
// Процедуры для работы с УСАПП и LCD
unsigned char USART_Receive( void );
void Data«rite<BYTE Data);
void CommandWrite(BYTE Command);
void ReadStatus(void);
void ReadStatus2(void);
void SendCoimand{BYTE Command);
void SendlByteCommand(BYTE Data, BYTE Command);
void Send2ByteCommand(WORD Data, BYTE Command);
void SetCursorPointer(WORD Position)
void SetAddressPointer(WORD Address)
void ByteWriteToRam(WORD AddressPointer, BYTE Data)
void AutoWrite(BYTE Data);
void mainf void )
BYTE HumBytes = 0;
InitAVR();
_SEI(); /* Разрешить прерывания */
while (!)
if(TmrOFlag) // Произошло срабатывание таймера
BYTE rec = 0;
while(DatalnReceiveBuffer() != 0) // Пока буффер не пуст
rec = USART_Receive(); // Приняли байт из буффера
OutString[NumBytes] = Rebuild(rec); // Записали его в строку NumBytes-n-;// Увеличить счетчик принятых байт
if (rec == OxOD)// Конец строки - ?
/* Выводим строку на LCD в режиме AutoWrite*/
AutoWriteModefO, —NumBytes)
for(int i = 0; i <= NumBytes; i++) OutStringU] = 0;
NumBytes = 0; }
\
TmrOFlag = 0;
} )
/* Процедура инициализации USART */ void USART_Init( unsigned int baudrate ) t
/* Установить частоту */
UBRROH = (unsigned char) (baudrate»8) ;
UBRROL = (unsigned char) baudrate;
/* Включить приемник UART */ UCSRB =
/* Процедура чтения из приемника */ BYTE USART_Receive( void
while ( USART_RxHead == USART_RxTail ) /* Ждем поступления данных */ ;
tmptail = USART_RxTail + 1; /* Рассчет индекса буффера */ USART_RxTail = tmptail;/* Сохранить новели индекс */
return USART_RxBuf[tmptail]; /* Вернуть данные */
>
unsigned char DatalnReceiveBuffer( void )
return ( USART_RxHead != USART_RxTail ); /* Возвращает О если буффер пуст */
/* Обработчик прерывания от приемника */ #pragma vector=USART_RXC_vect _interrupt void USART_RX_interrupt( void ) {
unsigned char data;
unsigned char tmphead;
/* Прочесть полученные данные */
/* Рассчет нового индекса */
tmphead = ( USARTJRxHead + 1 };
if ( tmphead == USART_RxTail ) (
USART_RxBuf[tmphead] = data; /* Сохранить полученные данные в буффере */ }
// Процедура инициализации таймера
void JnitTimer(void)
disable_interrupt();
/* Обработчик прерывания от таймера */ tfpragma vector=TIMERO_OVF_vect
TCNTO=TmrO_Reload;
TmrOFlag =1; }
void InitPortARead(void) {
DDRA = 0;
PORTA = Oxff; }
void InitPortAWrite(void) {
void InitPortCWrite(void) I
DDRC = Oxff;
PORTC = 0x30; }
void InitLCD(void) {
int tmp = 0;
Send2ByteComraand(tm.p, ET_TEXT_HOME_ADDRESS_COMMAND);
tmp = 0x14;
Send2ByteCommand(tmp, SET_TEXT_AREA_COMMAND);
tmp = 0x80;
CoromandWrite(INTERNAL_CG_ROM_MODE);
CommandWrite{TEXT_ON_GRAPHIC_OFF);
I
void InitAVR(void)
InitPortAWriteO ;
InitPortCWriteO ;
InitLCDO;
InitTimer();
USART_Init( 47 };//Установить частоту 9,600 используя 1.3728MHz кристалл
// Процедуры для работы с LCD-дисплеем void DataWrite(BYTE Data)
t
PINC = DATA_WRITE_COMMAND;
PIНА ~ Data; }
void CommandWrite(BYTE Command)
PINC = CCMMRND_WRITE_COMMAND;
Р1ЫА = Command; J
void ReadStatus(void) {
BYTE tempFlag = 0; BYTE stat; InitPortAReadO ; while(tempFlag != 1) (
PINC = READ_STATUS_COMMAND;
Stat = PIMH.;
if((stat & 0x03) == 0x03) tempFlag = 1; }
InitPortAWriteO }
void ReadStatusS(void)
BYTE tempFlag = 0; BYTE stat; InitPortAReadO; while(tempFlag != 1) {
stat = PINA;
if((stat b 0x08) == 0x08) tempFlag = 1; }
void SendCommandfBYTE Command)
ReadStatus{); WriteCommand(Command); }
void SendlByteCommandfBYTE Data, BYTE Command) {
ReadStatus();
DataWrite(Data);
ReadStatus{);
CommandWrite(Command); }
void Send2ByteCommand{WORD Data, BYTE Command) {
DataWrite((BYTE)Data);
DataHrite((BYTE)(Data » 8));
ReadStatus ();
// Position: младший байт - координата X (от OOh до 4Fh)
//старший байт - координата Y (от OOh до IFh)
Send2ByteComnand(Positon, SET_CURSOR_COMMAND);
// Address: младший байт
//старший байт
Serid2BytesCommand[Address, S£T_ADDRESS_COMMAND);
void ByteWriteToRamfWORD AddressPointer, BYTE Data)
SetAddressPointer(AddressPointer);
DataWrite (Data) ,-
DataWrite(DATAJWRITEjLNC_ADP); }
void AutoWrite(BYTE Data) (
ReadStatus2();
PINA = Data;
// Массив символов OutString должен быть объявлен как
// глобальный массив типа BYTE
WORD AutoWriteModefWORD Address, BYTE NumBytes)
SetAddressPointer(Address);
SendCommand(SET_DATA_AUTO_WRITE_COMMRND);
for(int i = 0; i < NumBytes; i++) {
SendCommand (AUTO_RESET_CCMMAND) ; return Address;
Страницы: 1, 2