#include #include "signals.h" #define BUFSIZE 95 //#define CLRWDT _asm clrwdt _endasm; typedef unsigned int word; word at 0x2007 CONFIG = 0x3F72; // для WDT: 0x3F76 unsigned char cmd, // полученная команда d_H, d_L, // старший и младший байты двухбайтной посылки T1H, T1L, // значения регистров счетчика таймера 1 mC_addr; // физ. адрес контроллера (константа, устанавливается функцией init) unsigned char SPI_buf[BUFSIZE], SPI_cntr; void send9bit(unsigned char something){ unsigned char tmp; something &= 0x1F; // сброс старших трех бит (там будет адрес) tmp = mC_addr | something; TXEN = 1; // готов к передаче TX9D = 0; // 0 - передает контроллер TXREG = tmp; // послать команду } unsigned char get9bit(){ unsigned char err1, err2, flag9bit, tmp; while(!RCIF); flag9bit = RX9D; err1 = FERR; err2 = OERR; // считать 9-й бит и ошибки cmd = RCREG; // очистить буфер данных RX9D = 0; if(err1 == 1){ // send9bit(NO_STOP_BIT); // не обнаружен стоповый бит return NO_STOP_BIT; } if(err2 == 1){ // send9bit(STACK_OVERFLOW); // переполнение приемных регистров CREN = 0; CREN = 1; // сбросить флаг ошибки return STACK_OVERFLOW; } if(flag9bit) return TWOBYTE; // данные - часть двухбайтной посылки (неизвестно еще чьей :) ) tmp = cmd & 0xE0; // выделение адреса из команды cmd &= 0x1F; // обнуление адресных битов if(tmp != mC_addr) return ERR_CMD; // если адресован чужому send9bit(cmd); // Эхо принятой команды return OK; } void sendword(unsigned char data_H, unsigned char data_L){ RCIE = 0; // disable USART in interrupt TMR1IE = 0; TXEN = 1; TX9D = 1; TXREG = data_H; while(!TRMT); TXEN = 1; TX9D = 1; TXREG = data_L; RCIE = 1; TMR1IE = 1; } unsigned char getword(){ unsigned char ret = 0; RCIE = 0; // disable USART in interrupt TMR1IE = 0; if(ten_times_read()){ d_H = cmd; if(ten_times_read()){ d_L = cmd; ret = 1;}} // если оба байта считали правильно TMR1IE = 1; RCIE = 1; // enable USART in interrupt return ret; } unsigned char ten_times_read(){ // 10 попыток чтения для двухбайтного приема unsigned char i=0; do i++; while(get9bit() != TWOBYTE && i < 10); if(i > 9){send9bit(ERR_CMD); return 0;} send9bit(OK); return 1; } void init(){ // инициализация // Настройка USART'a // TXSTA: | CSRC | TX9 | TXEN | SYNC | N/A | BRGH | TRMT | TX9D | TXSTA = 0x66; // (11000110): master, 9-ти битный ввод/вывод, async, hi-speed, ready // SPBRG - скорость передачи SPBRG = 25; // 9.6 кб/с // RCSTA: | SPEN | RX9 | SREN | CREN | ADDEN | FERR | OERR | RX9D | RCSTA = 0xD0; // ( 11010000): enable, 9bit, continuous mode // настройка портов: PORTA = 0; // 6-ти битный аналогово/цифровой порт (0..5 биты) // ADCON1: | ADFM | N/A | N/A | N/A | PCFG3 | PCFG2 | PCFG1 | PCFG0 | ADCON1 = 0x06; // Аналогово/цифровой порт работает в полностью цифровом режиме TRISA = 0; // направление порт А (1-вход, 0-выход) TRISB = 0xff; // --/ B /-- // OPTION_REG: | !RBPU | INTEDG | TOCS | TOSE | PSA | PS2 | PS1 | PS0 | OPTION_REG = 0x7f; /* (01111111) 0 - подключение подтяжек на порт B (уст. лог. 1), прерывание по нарастающему фронту RB0, таймер 0 работает по сигналу с RA4 таймер 0 увеличивается при спаде сигнала на RA4 предделитель подключен к сторожевому таймеру режим prescaler: 1:128 */ TRISC = 0xC0; // (11000000) - 0..5 биты как выходы INTCON = 0; // отключить все прерывания T1CON = 0; // PIE1: | PSPIE | ADIE | RCIE | TXIE | SSPIE | CCP1IE | TMR2IE | TMR1IE | PIE1 = 0x20; // (00100000): enable USART(in) // PIE2: все N/A, кроме EEIE (PIE2.4) PIE2 = 0; // & disable other int.s PORTB = 0; // INTCON: | GIE | PEIE | T0IE | INTE | RBIE | T0IF | INTF | RBIF | INTCON = 0xC0; // (1100000) - включить глобальные прерывания, прерывания по периферии PORTC = 0; // без напряжения PORTA = 0xF; // (00001111) // получение адреса mC_addr = PORTB; // физический адрес устройства mC_addr &= 0xE0; // выделение физического адреса SSPEN = 0; SSPIE = 1; SPI_cntr = 0; } void timer1set(){ // установка таймера // unsigned int tmp = 0xffff - usec/8; T1CON = 0; // выключить таймер TMR1IF = 0; // сбросить флаг прерывания TMR1IE = 1; // разр/запр прерывание TMR1H = T1H = d_H; //(tmp >> 8) & 0xff; TMR1L = T1L = d_L; //tmp & 0xff; // установить счетчики // T1CON: | - | - | T1CPS1 | T1CPS0 | T1OSCEN | T1SYNC | TMR1CS | TMR1ON | T1CON = 0x31; // (00110001) - включить таймер 1, предделитель на 1/8 (250 кГц) } void timer1int(){ // обработка прерываний первого таймера T1CON = 0; TMR1H = T1H; TMR1L = T1L; // send9bit(TEST); T1CON = 0x31; // снова запускаем таймер } void SPI_int(){ // в пассивном режиме принимаемые данные сохраняются в // буфер, при заполнении буфера он отсылается на ПК unsigned char i; if(SSPOV == 1) // ошибка переполнения буфера return; if(BF == 0) return; // буфер не заполнен SSPIE = 0; TMR1IE = 0; RCIE = 0; SPI_buf[SPI_cntr++] = SSPBUF; if(SPI_cntr == BUFSIZE){ for(i = 0; i < BUFSIZE; i++){ TXEN = 1; TXREG = SPI_buf[i]; while(!TRMT); } SPI_cntr = 0; } // BF = 0; RCIE = 1; TMR1IE = 1; SSPIF = 0; SSPIE = 1; } /* void SPI_int(){ SSPIE = 0; if(SSPOV == 1) // ошибка переполнения буфера return; if(BF == 0) return; // буфер не заполнен RCIE = 0; TMR1IE = 0; TXEN = 1; TXREG = SSPBUF; // отправляем полученный байт // while(!TRMT); RCIE = 1; TMR1IE = 1; BF = 0; SSPIF = 0; SSPIE = 1; }*/ void write_SPI(unsigned char byte){ SSPBUF = byte; //PORTA &= 0xEF; // -SS = 0 - передаем данные по SPI ведомому while(!SSPIF); // ждем окончания передачи // SPI_int(); if(SSPOV == 1) // ошибка переполнения буфера return; //if(BF == 0) return; // буфер не заполнен SSPIE = 0; RCIE = 0; TMR1IE = 0; TXEN = 1; TXREG = SSPBUF; // отправляем полученный байт while(!TRMT); RCIE = 1; TMR1IE = 1; // BF = 0; SSPIF = 0; SSPIE = 1; } void show_spi(){ unsigned char i; SSPIE = 0; RCIE = 0; TMR1IE = 0; TXEN = 1; TXREG = SPI_cntr; while(!TRMT); if(SPI_cntr > 0) for(i = 0; i < SPI_cntr; i++){ TXEN = 1; TXREG = SPI_buf[i]; while(!TRMT); } SPI_cntr = 0; TMR1IE = 1; BF = 0; SSPIF = 0; SSPIE = 1; } void on_interrupt() __interrupt 0{ // обработка прерываний if(RCIF == 1){ // поступило прерывание от USART if(get9bit() != OK) return; switch(cmd){ case INIT: init(); break; case SET_TIMER: if(getword()) timer1set(); else send9bit(ERR_CMD); break; case TMR_SETTINGS: sendword(T1H, T1L); break; case SPI_send: if(getword()){ write_SPI(d_H); write_SPI(d_L);} break; case SPI_send_one: while(!RCIF); write_SPI(RCREG); break; case IMP_RISE: CKE = 1; break;//данные передаются по заднему фронту case IMP_FALL: CKE = 0; break; //данные передаются по переднему фронту case MID_DATA: SMP = 0; break; case END_DATA: SMP = 1; break; case SPI_ON: // SPI // SSPCON: | WCOL | SSPOV | SSPEN | CKP | SSPM3 | SSPM2 | SSPM1 | SSPM0 | SSPEN = 1; // (00110010) - выключить SPI, высокий уровень CLK (CKP=1), частота Fosc/64 // SSPSTAT: | SMP | CKE | - | - | - | - | - | BF | // SSPSTAT = 0; // режим работы SPI: SMP=0 - опрос входа в середине периода // CKE=0 - данные передаются по заднему фронту SSPIE = 1; break; case SPI_OFF: SSPEN = 0; SSPIE = 0; break; case SPI_ACTIVE: SSPCON = 0x32; TRISC = 0xD0; CKE = 0; SSPIE = 1; break; //TRISC = 0xC0 case SPI_PASSIVE: SSPCON = 0x35; TRISC = 0xD8; CKE = 0; SSPIE = 1; break;//TRISC=255; case HIG_SPD: SPBRG = 1; break; // 115200 case MID_SPD: SPBRG = 12; break; // 19200 case TEST: T1CON = 0; TMR1IF = 0; break; case SPI_SHOW: show_spi(); break; } } if(TMR1IF == 1) // поступило прерывание от таймера timer1int(); // обработать прерывание if(SSPIF == 1) // прерывание от SPI SPI_int(); // обрабатываем } void main(){ // основной цикл init(); while(1){}; }