diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e12707a --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +*~ +*.bak +*.bck +*.o +.hg* +.dropbox.attr diff --git a/02-TEST/Frontend/FE.c b/02-TEST/Frontend/FE.c new file mode 100644 index 0000000..2b405d9 --- /dev/null +++ b/02-TEST/Frontend/FE.c @@ -0,0 +1,389 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "signals.h" // определения сигналов связи + +#define C_NO 224 // номер контроллера (старшие 3 бита) +int BAUD_RATE = B9600; + +struct termio oldtty, tty; // флаги для UART +struct termios oldt, newt; // флаги для консоли +//struct serial_struct old_extra_term; +int comfd; // Файловый дескриптор порта +char *comdev = "/dev/ttyS0"; // Устройство порта (потом переделать для запроса) + +void tty_sig(unsigned char rb); + +unsigned char crc(unsigned char data){ + unsigned char crc = data & 1; + unsigned int i; + for(i = 1; i<8; i++) crc ^= (data >> i) & 1; + return crc; +} + +void quit(int ex_stat){ // выход из программы + tcsetattr( STDIN_FILENO, TCSANOW, &oldt ); // возвращаем консоль в начальное состояние (на всякий случай) + ioctl(comfd, TCSANOW, &oldtty ); // восстанавливаем режим работы com + close(comfd); // закрываем соединение + printf("Выход... (сигнал %d)\n", ex_stat); + exit(ex_stat); +} + +void tty_init(){ + printf("\nОткрываю порт...\n"); + if ((comfd = open(comdev,O_RDWR|O_NOCTTY|O_NONBLOCK)) < 0){ + fprintf(stderr,"Can't use port %s\n",comdev); + quit(1); + } + printf(" OK\nПолучаю текущие настройки порта...\n"); + ioctl(comfd,TCGETA,&oldtty); // Узнаем текущие параметры порта + tty = oldtty; + tty.c_lflag = 0; // ~(ICANON | ECHO | ECHOE | ISIG) + tty.c_iflag = BRKINT; // подготовка к 9битной передаче + tty.c_oflag = 0; + tty.c_cflag = BAUD_RATE|CS8|CREAD|CLOCAL|PARENB; // 9.6к, 8N1, RW, игнорировать контр. линии + tty.c_cc[VMIN] = 0; // не канонический режим + tty.c_cc[VTIME] = 5; // (без символов ВК и пр.) + if(ioctl(comfd,TCSETA,&tty)<0) exit(-1); // Устанавливаем текущие параметры порта + printf(" OK\n"); +} + +unsigned char read_tty(unsigned char *byte){ + *byte = 0; + fd_set rfds; // набор файловых дескрипторов + struct timeval tv; // время ожидания + int retval; // возвращаемое ф-й select значение + tty.c_iflag &= ~PARODD; + ioctl(comfd,TCSETA,&tty); +// Ждем, сигнала с порта + FD_ZERO(&rfds); // очищаем набор + FD_SET(comfd, &rfds); // теперь это - свойства порта + tv.tv_sec = 0; tv.tv_usec = 50000; // ждем + retval = select(comfd + 1, &rfds, NULL, NULL, &tv); + if (!retval) return 0; // если сигнала нет, возвращаем ноль + if(FD_ISSET(comfd, &rfds)){ +// printf("ready "); + if(read(comfd, byte, 1) < 1) return 0; // ошибка считывания + } + else return 0; // ошибка +/* if(*byte == 8){ + return 0; + + } + else*/ +// printf("считан: %d (команда %d)\n", *byte, *byte & 0x1f); + return 1; +} + +unsigned char read_console(){ // считываем данные с консоли + unsigned char rb; + struct timeval tv; + int retval; + tcgetattr( STDIN_FILENO, &oldt ); // открываем терминал для реакции на клавиши без эха + newt = oldt; + newt.c_lflag &= ~( ICANON | ECHO ); + tcsetattr( STDIN_FILENO, TCSANOW, &newt ); + fd_set rfds; + FD_ZERO(&rfds); + FD_SET(STDIN_FILENO, &rfds); // 0 - стандартный вход + tv.tv_sec = 0; tv.tv_usec = 10000; // ждем 0.01с + retval = select(1, &rfds, NULL, NULL, &tv); + if (!retval) rb = 0; + else { + if(FD_ISSET(STDIN_FILENO, &rfds)) rb = getchar(); + else rb = 0; + } + tcsetattr( STDIN_FILENO, TCSANOW, &oldt ); + return rb; +} + +unsigned char mygetchar(){ // аналог getchar() без необходимости жать Enter + unsigned char ret; + do ret = read_console(); + while(ret == 0); + return ret; +} + +void write_tty_raw(unsigned char wb){ + if(crc(wb)) // нечетная сумма + tty.c_cflag |=PARODD; // 9-й бит = 0 + else + tty.c_cflag &= ~PARODD; // = 1 + ioctl(comfd,TCSETA,&tty); // перенастраиваем порт + if(write(comfd, &wb, 1) < 0) err("Ошибка! Запись не удалась :(\n"); // и пишем в него байт +} + +void write_tty(unsigned char wb){ + unsigned char tmp = wb; + tmp &= 0x1f; // на всякий случай очищаем от мусора + tmp |= C_NO; // добавляем к команде + write_tty_raw(tmp); +} + +int send_cmd(unsigned char cmd){ // посылка контроллеру команды с контролем + unsigned char rtn=ERR_CMD, byte=0, i=0; + while(i<2 && rtn != 1){ + write_tty(cmd); + usleep(100000); + rtn = read_tty(&byte); + byte &= 0x1f; + i++; + } + if(byte != cmd){ + printf("\n\n!!!!!! Ошибка! Контроллер не отвечает (ответ %d на команду %d) !!!!!\n\n", byte, cmd); + return 0; + } + else return 1; +} + +void sendword(unsigned int data){ + unsigned char tmp,i=0,rr=0, ret; + tmp = (data >> 8) & 0xFF; + if(crc(tmp)) // нечетная сумма + tty.c_cflag &= ~PARODD; // 9-й бит = 0 + else + tty.c_cflag |= PARODD; // = 1 + ioctl(comfd,TCSETA,&tty); // перенастраиваем порт + write(comfd, &tmp, 1); + do{ i++; + usleep(10000); + ret = read_tty(&rr); rr &= 0x1F; + }while((ret == 0 || rr != OK) && i < 10 ); + if(rr != OK){ err("Ошибка записи"); return;} + i = 0; + tmp = data & 0xFF; + if(crc(tmp)) // нечетная сумма + tty.c_cflag &= ~PARODD; // 9-й бит = 0 + else + tty.c_cflag |= PARODD; // = 1 + ioctl(comfd,TCSETA,&tty); // перенастраиваем порт + write(comfd, &tmp, 1); + do{ i++; + usleep(10000); + ret = read_tty(&rr); rr &= 0x1F; + }while((ret == 0 || rr != OK) && i < 10 ); + if(rr != OK){err("Неудача"); return;} +} + +void send_seq(){ + unsigned char seq[1024], byte; + char *line; + int cntr = 0, n, sz = 9; + line = (char*) malloc(10); + printf("\nВводите числа по одному в строке, окончание - слово end\n"); + do{ + n = getline(&line, &sz, stdin); + if(n == 0 || strstr(line, "end") != NULL) break; + seq[cntr++] = (unsigned char)atoi(line); + }while(cntr < 1024); + printf("\nНачинаю передачу\n"); + for(n=0; n>=1; + } + bin[8]=0; +} + +void tty_sig(unsigned char rb){ // обработка сигналов с контроллера + char bin[9]; + dec2bin(rb, bin); + switch(rb){ + case ERR_CMD: printf("Ошибка (\e[1;31;40m%d\e[0m?)\n", ERR_CMD); break; + case OK: printf("OK (\e[1;31;40m%d\e[0m?)\n", OK); break; + default: printf("\e[1;31;40m%d\e[0m\t(%s)\n", rb, bin); + } +} + +int main(int argc, char *argv[]){ + unsigned char rb, byte, i = 0; // считанные данные, счетчик + tty_init(); + rb = ERR_CMD; + signal(SIGTERM, quit); // kill (-15) + signal(SIGINT, quit); // ctrl+C + signal(SIGQUIT, SIG_IGN); // ctrl+\ . + signal(SIGTSTP, SIG_IGN); // ctrl+Z + setbuf(stdout, NULL); + printf("\nИнициализация...\n"); + do{ + write_tty(INIT); // Инициализация контроллера + rb = read_tty(&byte); + usleep(100000); + i ++; + } + while(i<3 && rb != 1); // проверка связи + if(i > 2 || (byte&0x1f) != INIT){ + fprintf(stderr,"\n!!!!!! Ошибка: контроллер не отвечает (%d) !!!!!!\n", byte); + } + else printf(" OK\n"); + while(1){ // бесконечно зацикливаемся + rb = read_console(); + if(rb != 0) con_sig(rb); // если что-то появилось - обрабатываем + rb = read_tty(&byte); + if(rb != 0) tty_sig(byte); // если есть сигнал с контроллера - обрабатываем + + } +} diff --git a/02-TEST/Frontend/main.c b/02-TEST/Frontend/main.c new file mode 100644 index 0000000..25eb978 --- /dev/null +++ b/02-TEST/Frontend/main.c @@ -0,0 +1,275 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "signals.h" // определения сигналов связи +#include "func.h" // функции обработки сигналов, глобальные переменные +#include "keys.h" // клавишные команды +#include "killbrothers.h" +#include "queues.h" + +#define CMSPAR 010000000000 +extern int get_auth_level(); +FILE* outfile; + +double tm0, tm; // время в секундах + +struct termio oldtty, tty; // флаги для UART +int comfd = -1; // Файловый дескриптор порта +static char *comdev = "/dev/ttyS1"; // Устройство порта (потом переделать для запроса) + +unsigned char crc(unsigned char data){ + unsigned char crc = data & 1; + unsigned int i; + for(i = 1; i<8; i++) crc ^= (data >> i) & 1; + return crc; +} + +double dtime(){ + struct timeval tv; + struct timezone tz; + int ret; + double t; + ret = gettimeofday(&tv, &tz); + t = (double)tv.tv_sec + (double)tv.tv_usec*0.000001; + t -= timezone; + return(t); +} + +void quit(int ex_stat){ // выход из программы + unsigned char i; + err("Отключаюсь..."); + if(comfd > 0){ + for(i=0; i<8; i++) + stop_motor(i<<5, "0"); // останавливаем двигатель + ioctl(comfd, TCSETA, &oldtty); // восстанавливаем режим работы com + close(comfd); // закрываем соединение + } + rm_queues(); + exit(ex_stat); +} + +void tty_init(){ + if ((comfd = open(comdev,O_RDWR|O_NOCTTY|O_NONBLOCK)) < 0) + die("Can't use port %s\n",comdev); + ioctl(comfd,TCGETA,&oldtty); // Узнаем текущие параметры порта + tty = oldtty; + tty.c_lflag = 0; + tty.c_iflag = BRKINT;//|PARENB|CMSPAR; + tty.c_oflag = 0; + tty.c_cflag = B9600|CS8|CREAD|CLOCAL|PARENB;//|CMSPAR; + tty.c_cflag &= ~PARODD; + tty.c_cc[VMIN] = 0; + tty.c_cc[VTIME] = 1; + ioctl(comfd,TCSETA,&tty); +} + +unsigned char read_tty(){ // считываем 1 байт (с ожиданием сигнала) + unsigned char rb; // то, что считываем + tty.c_iflag &= ~PARODD; // принимаем с девятым битом = 0 + ioctl(comfd,TCSETA,&tty); + if(read(comfd, &rb, 1) < 1) return 0; // ошибка считывания + tm = dtime() - tm0; + tm0 = dtime(); + fprintf(stderr,"считан сигнал: %d с контроллера %d, время от предыдущего считывания: %f с\n", rb&0x1F, rb&0xE0, tm); + return rb; +} + +void write_tty_raw(unsigned char wb){ + if(crc(wb)) // нечетная сумма + tty.c_cflag |=PARODD; // 9-й бит = 0 + else + tty.c_cflag &= ~PARODD; // = 1 + ioctl(comfd,TCSETA,&tty); // перенастраиваем порт + if(write(comfd, &wb, 1) < 0) err("Ошибка! Запись не удалась :(\n"); // и пишем в него байт +} + +void write_tty(unsigned char wb, unsigned char cno){ + unsigned char tmp = wb; + tmp &= 0x1f; // на всякий случай очищаем от мусора + tmp |= cno; // добавляем к команде + write_tty_raw(tmp); +} + +int send_cmd(unsigned char cmd, unsigned char flag, unsigned char cno){ // посылка контроллеру команды с контролем + // flag = 1 - команда отсылается текущему контроллеру, 0 - по запросу + int ret = -1; + unsigned char rtn=0, i=0, cmd1; + cmd1 = (flag)? ((cmd&0x1F)|cno) : cmd; + while(i<10 && rtn != cmd1){ // 10 попыток + usleep(1000); + if(flag) write_tty(cmd, cno); + else write_tty_raw(cmd); + usleep(100000); + rtn = read_tty(); + i++; + } + if(rtn != cmd1) + err("!!!!!! Ошибка! Контроллер не отвечает !!!!!"); + else ret = (i<2)?1:0; + return ret; +} + +void sendword(unsigned int data){ + unsigned char tmp,i=0,rr=0; + tmp = (data >> 8) & 0xFF; + if(crc(tmp)) // нечетная сумма + tty.c_cflag &= ~PARODD; // 9-й бит = 0 + else + tty.c_cflag |= PARODD; // = 1 + ioctl(comfd,TCSETA,&tty); // перенастраиваем порт + do{ i++; + if(write(comfd, &tmp, 1) < 0){continue;} + usleep(10000); + rr = read_tty() & 0x1F; + }while(rr != OK && i < 10); + if(rr != OK){ err("Ошибка записи"); return;} + i = 0; + tmp = data & 0xFF; + if(crc(tmp)) // нечетная сумма + tty.c_cflag &= ~PARODD; // 9-й бит = 0 + else + tty.c_cflag |= PARODD; // = 1 + ioctl(comfd,TCSETA,&tty); // перенастраиваем порт + do{ i++; + if(write(comfd, &tmp, 1) < 0){continue;} + usleep(10000); + rr = read_tty() & 0x1F; + }while(rr != OK && i < 10); + if(rr != OK){err("Неудача"); return;} +} + +/* +int getl(int fd, char* data, int N){ + int rb = 0, i=0; + char *ptr = data; + do{ + if((rb = read(fd, ptr, 1)) != 1) break; + if(*ptr == '\0' || *ptr == '\n') break; + ptr++; + }while(++i < N); + if(rb != 1 && i == 0) return (-1); + *ptr = '\0'; + return i; +}*/ + +void tmrset(unsigned char cno){ + unsigned char t_h,t_l; + float period; + if(send_cmd(TMR_SETTINGS, 1, cno)<0) return; + usleep(10000); + read(comfd, &t_h, 1); + usleep(10000); + read(comfd, &t_l, 1); + period = (65536.0 - 256.0*(float)t_h - (float)t_l)/125000.0; + warn("Период таймера: T=%f", period); +} + +void init_ctrlr(unsigned char cno){ + unsigned char rb = ERR_CMD; + unsigned char ini = INIT | cno; + int i=0; + warn("Инициализация..."); + do{ + write_tty(INIT, cno); // Инициализация контроллера + rb = read_tty(); + usleep(100000); + i++; + } + while(i<10 && rb != ini); // проверка связи + if(i > 9 || rb != ini){ + err("!!!!!! Ошибка: контроллер не отвечает !!!!!!"); + } + else{ + warn("... успешно."); + } +} + +void con_sig(unsigned char cno, unsigned char rb, char *val){ // обработка сигналов с консоли + //fprintf(stderr, "key: %c, cno: %d, val:%s\n", rb, cno, val); + switch(rb){ + case KEY_QUIT: quit(0); break; + case KEY_DEVICE: set_dev(cno, val); break; + case KEY_LEFT: rotate_left(cno, val); break; + case KEY_RIGHT: rotate_right(cno, val); break; + case KEY_NR: steps_(cno,RIGHT, val); break; + case KEY_NL: steps_(cno,LEFT, val); break; + case KEY_STOP: stop_motor(cno, val); break; + case KEY_VOLTAGE: set_voltage(cno, val); break; + case KEY_TMR: set_timer(cno, val); break; + case KEY_TMR_STOP: send_cmd(STOP_TIMER, 1, cno); break; + case KEY_TMR_STNGS: tmrset(cno); break; + case KEY_INIT: init_ctrlr(cno); break; + case KEY_Xplus: corrector(cno,0, val); break; + case KEY_Xminus: corrector(cno,1, val); break; + case KEY_Yplus: corrector(cno,2, val); break; + case KEY_Yminus: corrector(cno,3, val); break; + case KEY_MIDDLE: goto_middle(cno); break; + case KEY_TEST: send_cmd(TEST,1, cno); break; + +/* default: send_cmd(rb, 0); // спец. команда (для выделенных контроллеров) + data = read_int(); + if(data != -1) sendword(data); */ + } +} + +void tty_sig(unsigned char rb){ // обработка сигналов с контроллера + unsigned char cno = rb & 0xE0; + rb &= 0x1F; + switch(rb){ + case TERMINAL_: terminals(cno); break; // обработка концевиков + case STACK_OVERFLOW: error(STACK_OVERFLOW, cno); break; // переполнение стека RX контроллера + case NO_STOP_BIT: error(NO_STOP_BIT, cno); break; + } +} + +int main(int argc, char *argv[]){ + unsigned char rb, key;// считанные данные, счетчик + char *val; + setbuf(stdout, NULL); + printf("Content-type: multipart/form-data; charset=koi8-r\n\n"); + if(!killbrothers()) die("Не могу гарантировать монопольный доступ.."); + printf("Перехожу в режим демона\n"); + umask(0); + mk_queues(); + val = calloc(512, 1); + tty_init(); + close(0); close(1); close(2); // отключаемся от терминала + if(fork() != 0) exit(0); // закрываем родительский поток + if(argc > 1){ //comdev = argv[1]; + if(strcmp(argv[1], "XY") == 0){ + warn("Режим XY-актуаторов\n"); + if(init_motor(MOTOR_X)==0){ // двигатель Y + err("Y: Ошибка !"); + } + if(init_motor(MOTOR_Y)==0){ // двигатель X + err("X: Ошибка!"); + } + } + } + else + warn("Обычный режим работы"); + signal(SIGTERM, quit); // kill (-15) + signal(SIGINT, quit); // ctrl+C + signal(SIGQUIT, SIG_IGN); // ctrl+\ . + signal(SIGTSTP, SIG_IGN); // ctrl+Z + tm0 = dtime(); + while(1){ // бесконечно зацикливаемся + if(read_queue(&rb, &key, val) > 0){ + if(key != 0) con_sig(rb, key, val); // если что-то появилось - обрабатываем + } + rb = read_tty(); + if(rb != 0) tty_sig(rb); // если есть сигнал с контроллера - обрабатываем + } +} + diff --git a/02-TEST/Frontend/signals.h b/02-TEST/Frontend/signals.h new file mode 100644 index 0000000..aee6ac9 --- /dev/null +++ b/02-TEST/Frontend/signals.h @@ -0,0 +1,39 @@ +/*********** Перечень команд ************/ +// получить с компьютера два байта данных и записать их в SPI +#define SPI_send 1 +// режимы работы SPI +#define IMP_RISE 2 +#define IMP_FALL 3 +#define SPI_ON 4 +#define SPI_OFF 5 +#define SPI_ACTIVE 6 +#define SPI_PASSIVE 7 +#define MID_DATA 8 +#define END_DATA 9 + +#define SPI_SHOW 14 + +// скорости порта (по умолчанию 9600) +#define MID_SPD 15 +#define HIG_SPD 16 +// записать в порт один полученный байт +#define SPI_send_one 17 +// текущий период таймера +#define TMR_SETTINGS 18 +// установить значение таймера +#define SET_TIMER 26 +// сброс +#define INIT 28 +#define TEST 29 +/************** Ошибки и сигналы контроллера ******************/ +// все в порядке +#define OK 22 +// нет стопового бита +#define NO_STOP_BIT 24 +// переполнение регистров +#define STACK_OVERFLOW 25 +// ошибочкая команда +#define ERR_CMD 31 + +#define TWOBYTE 33 // двухбайтная посылка + diff --git a/02-TEST/main.c b/02-TEST/main.c new file mode 100644 index 0000000..7480b3b --- /dev/null +++ b/02-TEST/main.c @@ -0,0 +1,274 @@ +#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){}; +} + diff --git a/02-TEST/main1.c b/02-TEST/main1.c new file mode 100644 index 0000000..a208de6 --- /dev/null +++ b/02-TEST/main1.c @@ -0,0 +1,242 @@ +#include +#include "signals.h" +//#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[64], 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 = 0; + 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; + TMR1IE = 0; + RCIE = 0; + SPI_buf[SPI_cntr++] = SSPBUF; + if(SPI_cntr == 64){ + for(i = 0; i < 64; i++){ + TXEN = 1; + TXREG = SPI_buf[i]; + while(!TRMT); + } + SPI_cntr = 0; + } + RCIE = 1; + TMR1IE = 1; + BF = 0; + SSPIF = 0; +} + + + +/* +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(); + + RCIE = 0; + TMR1IE = 0; + TXEN = 1; + TXREG = SSPBUF; // отправляем полученный байт + RCIE = 1; + TMR1IE = 1; + BF = 0; + SSPIF = 0; +} + +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 = 0; break; + case SPI_OFF: SSPEN = 0; SSPIE = 0; break; + case SPI_ACTIVE: SSPCON = 0x32; TRISC = 0x10; CKE = 0; SSPIE = 0; break; //TRISC = 0xC0; + case SPI_PASSIVE: SSPCON = 0x35; TRISC = 0x18; 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; + } + } + if(TMR1IF == 1) // поступило прерывание от таймера + timer1int(); // обработать прерывание + if(SSPIF == 1) // прерывание от SPI + SPI_int(); // обрабатываем +} + +void main(){ // основной цикл + init(); + while(1){}; +} + diff --git a/02-TEST/run b/02-TEST/run new file mode 100755 index 0000000..61eb4d8 --- /dev/null +++ b/02-TEST/run @@ -0,0 +1,3 @@ +#!/bin/sh +sdcc -V -mpic14 -p16f873a main.c +#packihx main.ihx > main.hex diff --git a/02-TEST/signals.h b/02-TEST/signals.h new file mode 100644 index 0000000..6a42ea6 --- /dev/null +++ b/02-TEST/signals.h @@ -0,0 +1,50 @@ +/*********** Функции ***********************/ +void send9bit(unsigned char something); +unsigned char get9bit(); +void sendword(unsigned char data_H, unsigned char data_L); +unsigned char getword(); +unsigned char ten_times_read(); +void init(); +void timer1set(); +void timer1int(); +void SPI_int(); + +/*********** Перечень команд ************/ +// получить с компьютера два байта данных и записать их в SPI +#define SPI_send 1 +// режимы работы SPI +#define IMP_RISE 2 +#define IMP_FALL 3 +#define SPI_ON 4 +#define SPI_OFF 5 +#define SPI_ACTIVE 6 +#define SPI_PASSIVE 7 +#define MID_DATA 8 +#define END_DATA 9 + + +#define SPI_SHOW 14 + +// скорости порта (по умолчанию 9600) +#define MID_SPD 15 +#define HIG_SPD 16 +// записать в порт один полученный байт +#define SPI_send_one 17 +// текущий период таймера +#define TMR_SETTINGS 18 +// установить значение таймера +#define SET_TIMER 26 +// сброс +#define INIT 28 +#define TEST 29 +/************** Ошибки и сигналы контроллера ******************/ +// все в порядке +#define OK 22 +// нет стопового бита +#define NO_STOP_BIT 24 +// переполнение регистров +#define STACK_OVERFLOW 25 +// ошибочкая команда +#define ERR_CMD 31 + +#define TWOBYTE 33 // двухбайтная посылка diff --git a/03-focusing/Frontend/FE.c b/03-focusing/Frontend/FE.c new file mode 100644 index 0000000..e8164f0 --- /dev/null +++ b/03-focusing/Frontend/FE.c @@ -0,0 +1,413 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "signals.h" // определения сигналов связи + +#define C_NO 224 // номер контроллера (старшие 3 бита) +int BAUD_RATE = B9600; + +struct termio oldtty, tty; // флаги для UART +struct termios oldt, newt; // флаги для консоли +//struct serial_struct old_extra_term; +int comfd; // Файловый дескриптор порта +char *comdev = "/dev/ttyS0"; // Устройство порта (потом переделать для запроса) + +void tty_sig(unsigned char rb); + +unsigned char crc(unsigned char data){ + unsigned char crc = data & 1; + unsigned int i; + for(i = 1; i<8; i++) crc ^= (data >> i) & 1; + return crc; +} + +void quit(int ex_stat){ // выход из программы + tcsetattr( STDIN_FILENO, TCSANOW, &oldt ); // возвращаем консоль в начальное состояние (на всякий случай) + ioctl(comfd, TCSANOW, &oldtty ); // восстанавливаем режим работы com + close(comfd); // закрываем соединение + printf("Выход... (сигнал %d)\n", ex_stat); + exit(ex_stat); +} + +void tty_init(){ + printf("\nОткрываю порт...\n"); + if ((comfd = open(comdev,O_RDWR|O_NOCTTY|O_NONBLOCK)) < 0){ + fprintf(stderr,"Can't use port %s\n",comdev); + quit(1); + } + printf(" OK\nПолучаю текущие настройки порта...\n"); + ioctl(comfd,TCGETA,&oldtty); // Узнаем текущие параметры порта + tty = oldtty; + tty.c_lflag = 0; // ~(ICANON | ECHO | ECHOE | ISIG) + tty.c_iflag = BRKINT; // подготовка к 9битной передаче + tty.c_oflag = 0; + tty.c_cflag = BAUD_RATE|CS8|CREAD|CLOCAL|PARENB; // 9.6к, 8N1, RW, игнорировать контр. линии + tty.c_cc[VMIN] = 0; // не канонический режим + tty.c_cc[VTIME] = 5; // (без символов ВК и пр.) + if(ioctl(comfd,TCSETA,&tty)<0) exit(-1); // Устанавливаем текущие параметры порта + printf(" OK\n"); +} + +unsigned char read_tty(unsigned char *byte){ + *byte = 0; + fd_set rfds; // набор файловых дескрипторов + struct timeval tv; // время ожидания + int retval; // возвращаемое ф-й select значение + tty.c_iflag &= ~PARODD; + ioctl(comfd,TCSETA,&tty); +// Ждем, сигнала с порта + FD_ZERO(&rfds); // очищаем набор + FD_SET(comfd, &rfds); // теперь это - свойства порта + tv.tv_sec = 0; tv.tv_usec = 50000; // ждем + retval = select(comfd + 1, &rfds, NULL, NULL, &tv); + if (!retval) return 0; // если сигнала нет, возвращаем ноль + if(FD_ISSET(comfd, &rfds)){ +// printf("ready "); + if(read(comfd, byte, 1) < 1) return 0; // ошибка считывания + } + else return 0; // ошибка +/* if(*byte == 8){ + return 0; + + } + else*/ +// printf("считан: %d (команда %d)\n", *byte, *byte & 0x1f); + return 1; +} + +unsigned char read_console(){ // считываем данные с консоли + unsigned char rb; + struct timeval tv; + int retval; + tcgetattr( STDIN_FILENO, &oldt ); // открываем терминал для реакции на клавиши без эха + newt = oldt; + newt.c_lflag &= ~( ICANON | ECHO ); + tcsetattr( STDIN_FILENO, TCSANOW, &newt ); + fd_set rfds; + FD_ZERO(&rfds); + FD_SET(STDIN_FILENO, &rfds); // 0 - стандартный вход + tv.tv_sec = 0; tv.tv_usec = 10000; // ждем 0.01с + retval = select(1, &rfds, NULL, NULL, &tv); + if (!retval) rb = 0; + else { + if(FD_ISSET(STDIN_FILENO, &rfds)) rb = getchar(); + else rb = 0; + } + tcsetattr( STDIN_FILENO, TCSANOW, &oldt ); + return rb; +} + +unsigned char mygetchar(){ // аналог getchar() без необходимости жать Enter + unsigned char ret; + do ret = read_console(); + while(ret == 0); + return ret; +} + +void write_tty_raw(unsigned char wb){ + if(crc(wb)) // нечетная сумма + tty.c_cflag |=PARODD; // 9-й бит = 0 + else + tty.c_cflag &= ~PARODD; // = 1 + ioctl(comfd,TCSETA,&tty); // перенастраиваем порт + if(write(comfd, &wb, 1) < 0) fprintf(stderr, "Ошибка! Запись не удалась :(\n"); // и пишем в него байт +} + +void write_tty(unsigned char wb){ + unsigned char tmp = wb; + tmp &= 0x1f; // на всякий случай очищаем от мусора + tmp |= C_NO; // добавляем к команде + write_tty_raw(tmp); +} + +int send_cmd(unsigned char cmd){ // посылка контроллеру команды с контролем + unsigned char rtn=ERR_CMD, byte=0, i=0; + while(i<2 && rtn != 1){ + write_tty(cmd); + usleep(100000); + rtn = read_tty(&byte); + byte &= 0x1f; + i++; + } + if(byte != cmd){ + printf("\n\n!!!!!! Ошибка! Контроллер не отвечает (ответ %d на команду %d) !!!!!\n\n", byte, cmd); + return 0; + } + else return 1; +} + +void sendword(unsigned int data){ + unsigned char tmp,i=0,rr=0, ret; + tmp = (data >> 8) & 0xFF; + if(crc(tmp)) // нечетная сумма + tty.c_cflag &= ~PARODD; // 9-й бит = 0 + else + tty.c_cflag |= PARODD; // = 1 + ioctl(comfd,TCSETA,&tty); // перенастраиваем порт + write(comfd, &tmp, 1); + do{ i++; + usleep(10000); + ret = read_tty(&rr); rr &= 0x1F; + }while((ret == 0 || rr != OK) && i < 10 ); + if(rr != OK){ fprintf(stderr, "Ошибка записи"); return;} + i = 0; + tmp = data & 0xFF; + if(crc(tmp)) // нечетная сумма + tty.c_cflag &= ~PARODD; // 9-й бит = 0 + else + tty.c_cflag |= PARODD; // = 1 + ioctl(comfd,TCSETA,&tty); // перенастраиваем порт + write(comfd, &tmp, 1); + do{ i++; + usleep(10000); + ret = read_tty(&rr); rr &= 0x1F; + }while((ret == 0 || rr != OK) && i < 10 ); + if(rr != OK){fprintf(stderr, "Неудача"); return;} +} + +void send_rand(){ + int i, j = 0; unsigned char byte, rb; + srand(time(NULL)); + for(i=0; i<128; i++) + if(send_cmd(SPI_send_one)){ + write_tty_raw(25); + printf("%d: передан байт \e[1;32;40m18\e[0m\n",i); + if(read_tty(&byte)) + tty_sig(byte); + rb = read_console(); + if(rb == 'q') break; + //byte = (rand()|rand()) & 0xff; + byte = j++; + if(send_cmd(SPI_send_one)){ + write_tty_raw(byte); + printf("%d: передан байт \e[1;32;40m%d\e[0m\n", i, byte); + if(read_tty(&byte)) + tty_sig(byte); + rb = read_console(); + if(rb == 'q') break; + } + if(send_cmd(SPI_send_one)){ + write_tty_raw(0); + printf("%d: передан байт \e[1;32;40m0\e[0m\n", i); + if(read_tty(&byte)) + tty_sig(byte); + rb = read_console(); + if(rb == 'q') break; + } + } + +} + +void send_nseq(){ + int i, j; unsigned char byte, rb; + for(i=0; i<256; i++) + if(send_cmd(SPI_send_one)){ + byte = (unsigned char)i; + write_tty_raw(byte); + printf("%d: передан байт \e[1;32;40m%d\e[0m\n", i, byte); + if(read_tty(&byte)) + tty_sig(byte); + rb = read_console(); + if(rb == 'q') return; + for(j=0; j<5; j++) + if(send_cmd(SPI_send_one)){ + write_tty_raw(0); + printf("%d: передан байт \e[1;32;40m0\e[0m\n", i); + if(read_tty(&byte)) + tty_sig(byte); + rb = read_console(); + if(rb == 'q') return; + } + } + +} + +void send_seq(){ + unsigned char seq[1024], byte; + char *line; + int cntr = 0, n, sz = 9; + line = (char*) malloc(10); + printf("\nВводите числа по одному в строке, окончание - слово end\n"); + do{ + n = getline(&line, &sz, stdin); + if(n == 0 || strstr(line, "end") != NULL) break; + seq[cntr++] = (unsigned char)atoi(line); + }while(cntr < 1024); + printf("\nНачинаю передачу\n"); + for(n=0; n>=1; + } + bin[8]=0; +} + +void tty_sig(unsigned char rb){ // обработка сигналов с контроллера + char bin[9]; + dec2bin(rb, bin); + switch(rb){ + case ERR_CMD: printf("Ошибка (\e[1;31;40m%d\e[0m?)\n", ERR_CMD); break; + case OK: printf("OK (\e[1;31;40m%d\e[0m?)\n", OK); break; + default: printf("\e[1;31;40m%d\e[0m\t(%s)\n", rb, bin); + } +} + +int main(int argc, char *argv[]){ + unsigned char rb, byte, i = 0; // считанные данные, счетчик + tty_init(); + rb = ERR_CMD; + signal(SIGTERM, quit); // kill (-15) + signal(SIGINT, quit); // ctrl+C + signal(SIGQUIT, SIG_IGN); // ctrl+\ . + signal(SIGTSTP, SIG_IGN); // ctrl+Z + setbuf(stdout, NULL); + printf("\nИнициализация...\n"); + do{ + write_tty(INIT); // Инициализация контроллера + rb = read_tty(&byte); + usleep(100000); + i ++; + } + while(i<3 && rb != 1); // проверка связи + if(i > 2 || (byte&0x1f) != INIT){ + fprintf(stderr,"\n!!!!!! Ошибка: контроллер не отвечает (%d) !!!!!!\n", byte); + } + else printf(" OK\n"); + while(1){ // бесконечно зацикливаемся + rb = read_console(); + if(rb != 0) con_sig(rb); // если что-то появилось - обрабатываем + rb = read_tty(&byte); + if(rb != 0) tty_sig(byte); // если есть сигнал с контроллера - обрабатываем + + } +} diff --git a/03-focusing/Frontend/Makefile b/03-focusing/Frontend/Makefile new file mode 100644 index 0000000..8a80410 --- /dev/null +++ b/03-focusing/Frontend/Makefile @@ -0,0 +1,18 @@ +PROGRAM = FE +LOADLIBES = +CXX.SRCS = FE.c +CC = gcc +DEFINES = +CXX = gcc +CPPFLAGS = -Wall $(DEFINES) +OBJS = $(CXX.SRCS:.c=.o) +all : $(PROGRAM) clean +$(PROGRAM) : $(OBJS) + $(CC) $(CPPFLAGS) $(OBJS) $(LOADLIBES) -o $(PROGRAM) +clean: + /bin/rm -f *.o *~ +depend: + $(CXX) -MM $(CXX.SRCS) + +### +# name1.o : header1.h header2.h ... diff --git a/03-focusing/Frontend/signals.h b/03-focusing/Frontend/signals.h new file mode 100644 index 0000000..0d56dec --- /dev/null +++ b/03-focusing/Frontend/signals.h @@ -0,0 +1,44 @@ +/*********** Перечень команд ************/ +// получить с компьютера байт данных и записать в SPI +#define SPI_send_one 1 +// режимы работы SPI +#define MID_DATA 2 +#define END_DATA 3 +// скорости порта (по умолчанию 9600) +#define MID_SPD 4 // 19200 +#define LOW_SPD 5 // 9600 +// скорости объектива (время, через которое будет послан сигнал "стоп") +#define SPEED1 6 // .3c +#define SPEED2 7 // .05c +#define SPEED3 8 // .01c +// направления движения +#define FORW 9 +#define BACK 10 +#define INFTY 11 +#define ZERO 12 +// узнать фокус +#define FOCUS 19 +// ручной режим управления +#define HANDS 13 +#define TMR_ON 14 +#define TMR_OFF 15 +#define SPI_ON 16 +#define SPI_OFF 17 +// текущий период таймера +#define TMR_SETTINGS 18 +// установить значение таймера +#define SET_TIMER 26 +// сброс +#define INIT 28 +#define TEST 29 +/************** Ошибки и сигналы контроллера ******************/ +// все в порядке +#define OK 22 +// нет стопового бита +#define NO_STOP_BIT 24 +// переполнение регистров +#define STACK_OVERFLOW 25 +// ошибочкая команда +#define ERR_CMD 31 + +#define TWOBYTE 33 // двухбайтная посылка diff --git a/03-focusing/main.c b/03-focusing/main.c new file mode 100644 index 0000000..e93b382 --- /dev/null +++ b/03-focusing/main.c @@ -0,0 +1,227 @@ +#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) + tmr_on; // ==1 - таймер включен + +unsigned char write_SPI(unsigned char); +void hands(){ + unsigned char i; + write_SPI(10); // инициализация + write_SPI(0); +/* write_SPI(128); + for(i=0; i<20; i++) + write_SPI(0);*/ + write_SPI(94); // руки + for(i=0; i<5; i++) + write_SPI(0); + T1CON = 0; +} + +void focus(){ + unsigned char i; + write_SPI(194); + TX9D = 0; + for(i=0; i<5; i++){ + TXEN = 1; + TXREG = write_SPI(0); + while(!TRMT); + } +} + +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){ + return NO_STOP_BIT; + } + if(err2 == 1){ + 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 + TMR1IF = 0; + TMR1IE = 0; + TXEN = 1; + TX9D = 1; + TXREG = data_H; + while(!TRMT); + TXEN = 1; + TX9D = 1; + TXREG = data_L; + RCIE = 1; + if(tmr_on) TMR1IE = 1; +} + +unsigned char getword(){ + unsigned char ret = 0; + RCIE = 0; // disable USART in interrupt + TMR1IF = 0; + TMR1IE = 0; + if(ten_times_read()){ + d_H = cmd; + if(ten_times_read()){ + d_L = cmd; + ret = 1;}} // если оба байта считали правильно + if(tmr_on) 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; // выделение физического адреса + // SSPCON: | WCOL | SSPOV | SSPEN | CKP | SSPM3 | SSPM2 | SSPM1 | SSPM0 | + SSPCON = 0x32; // (00110010) - включить SPI, высокий уровень CLK (CKP=1), частота Fosc/64 + // SSPSTAT: | SMP | CKE | - | - | - | - | - | BF | + SSPSTAT = 0; // режим работы SPI: SMP=0 - опрос входа в середине периода + // CKE=0 - данные передаются по заднему фронту + TRISC = 0xD0; SSPIE = 1; + tmr_on = 0; + hands(); +} + +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 кГц) + tmr_on = 1; +} + +unsigned char write_SPI(unsigned char byte){ + unsigned char ans; + TMR1IF = 0; + if(tmr_on){ + T1CON = 0; // отключаем таймер + TMR1IE = 0; + } + SSPBUF = byte; + while(!SSPIF); // ждем окончания передачи + ans = SSPBUF; // регистрируем полученный байт + SSPIF = 0; + SSPIE = 1; + if(tmr_on){ + TMR1H = T1H; TMR1L = T1L; + T1CON = 0x31; // запускаем таймер + TMR1IE = 1; + } + return ans; +} + +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_one: while(!RCIF); + TX9D = 0; TXEN = 1; TXREG = write_SPI(RCREG); break; + case SPI_ON: SSPEN = 1; SSPIE = 1; break; + case SPI_OFF: SSPEN = 0; SSPIE = 0; break; + case MID_DATA: SMP = 0; break; + case END_DATA: SMP = 1; break; + case MID_SPD: SPBRG = 12; break; // 19200 + case LOW_SPD: SPBRG = 25; break; // 9600 + case SPEED1: d_H = 0x6D; d_L = 0x84; timer1set(); break; // 0.3с + case SPEED2: d_H = 0xE7; d_L = 0x96; timer1set(); break; // 0.05с + case SPEED3: d_H = 0xFB; d_L = 0x1E; timer1set(); break; // 0.01с + case FORW: write_SPI(5); break; + case BACK: write_SPI(6); break; + case INFTY: write_SPI(37); break; + case ZERO: write_SPI(22); break; + case HANDS: hands(); break; + case TMR_OFF: tmr_on = 0; T1CON = 0; TMR1IE = 0; break; + case TMR_ON: tmr_on = 1; T1CON = 0x31; TMR1IE = 1; break; + case FOCUS: focus(); break; + } + } + if(TMR1IF == 1 && tmr_on){ // поступило прерывание от таймера + write_SPI(4); // посылаем сигнал стоп и перезапускаем таймер + write_SPI(0); + } +} + +void main(){ // основной цикл + init(); + while(1){}; +} + diff --git a/03-focusing/main1.c b/03-focusing/main1.c new file mode 100644 index 0000000..a208de6 --- /dev/null +++ b/03-focusing/main1.c @@ -0,0 +1,242 @@ +#include +#include "signals.h" +//#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[64], 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 = 0; + 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; + TMR1IE = 0; + RCIE = 0; + SPI_buf[SPI_cntr++] = SSPBUF; + if(SPI_cntr == 64){ + for(i = 0; i < 64; i++){ + TXEN = 1; + TXREG = SPI_buf[i]; + while(!TRMT); + } + SPI_cntr = 0; + } + RCIE = 1; + TMR1IE = 1; + BF = 0; + SSPIF = 0; +} + + + +/* +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(); + + RCIE = 0; + TMR1IE = 0; + TXEN = 1; + TXREG = SSPBUF; // отправляем полученный байт + RCIE = 1; + TMR1IE = 1; + BF = 0; + SSPIF = 0; +} + +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 = 0; break; + case SPI_OFF: SSPEN = 0; SSPIE = 0; break; + case SPI_ACTIVE: SSPCON = 0x32; TRISC = 0x10; CKE = 0; SSPIE = 0; break; //TRISC = 0xC0; + case SPI_PASSIVE: SSPCON = 0x35; TRISC = 0x18; 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; + } + } + if(TMR1IF == 1) // поступило прерывание от таймера + timer1int(); // обработать прерывание + if(SSPIF == 1) // прерывание от SPI + SPI_int(); // обрабатываем +} + +void main(){ // основной цикл + init(); + while(1){}; +} + diff --git a/03-focusing/run b/03-focusing/run new file mode 100755 index 0000000..61eb4d8 --- /dev/null +++ b/03-focusing/run @@ -0,0 +1,3 @@ +#!/bin/sh +sdcc -V -mpic14 -p16f873a main.c +#packihx main.ihx > main.hex diff --git a/03-focusing/signals.h b/03-focusing/signals.h new file mode 100644 index 0000000..3012ba6 --- /dev/null +++ b/03-focusing/signals.h @@ -0,0 +1,55 @@ +/*********** Функции ***********************/ +void send9bit(unsigned char something); +unsigned char get9bit(); +void sendword(unsigned char data_H, unsigned char data_L); +unsigned char getword(); +unsigned char ten_times_read(); +void init(); +void timer1set(); +void timer1int(); +void SPI_int(); + +/*********** Перечень команд ************/ +// получить с компьютера байт данных и записать в SPI +#define SPI_send_one 1 +// режимы работы SPI +#define MID_DATA 2 +#define END_DATA 3 +// скорости порта (по умолчанию 9600) +#define MID_SPD 4 // 19200 +#define LOW_SPD 5 // 9600 +// скорости объектива (время, через которое будет послан сигнал "стоп") +#define SPEED1 6 // .3c +#define SPEED2 7 // .05c +#define SPEED3 8 // .01c +// направления движения +#define FORW 9 +#define BACK 10 +#define INFTY 11 +#define ZERO 12 +// узнать фокус +#define FOCUS 19 +// ручной режим управления +#define HANDS 13 +#define TMR_ON 14 +#define TMR_OFF 15 +#define SPI_ON 16 +#define SPI_OFF 17 +// текущий период таймера +#define TMR_SETTINGS 18 +// установить значение таймера +#define SET_TIMER 26 +// сброс +#define INIT 28 +#define TEST 29 +/************** Ошибки и сигналы контроллера ******************/ +// все в порядке +#define OK 22 +// нет стопового бита +#define NO_STOP_BIT 24 +// переполнение регистров +#define STACK_OVERFLOW 25 +// ошибочкая команда +#define ERR_CMD 31 + +#define TWOBYTE 33 // двухбайтная посылка diff --git a/opisanie.pdf b/opisanie.pdf new file mode 100644 index 0000000..19e5b2b Binary files /dev/null and b/opisanie.pdf differ diff --git a/opisanie.tex b/opisanie.tex new file mode 100644 index 0000000..9f2b027 --- /dev/null +++ b/opisanie.tex @@ -0,0 +1,416 @@ +\documentclass[a4paper,12pt]{extarticle} +\usepackage{/home/eddy/ed} +\title{Протокол управления объективами Canon EF} +\author{} +\FDL +\begin{document} +\maketitle +\section{Методика <<взлома>>} +Для работы со SPI--интерфейсом объектива использовался микроконтроллер PIC16F873a, +подключенный к персональному компьютера через интерфейс~RS--232. +Так как кварцевый резонатор контроллера имел частоту~$f_{osc}=4\,$МГц, пришлось ограничиться +довольно медленной скоростью~--- 19.2\,кбит/с. + +SPI--интерфейс контроллера был настроен на скорость передачи сообщений~$f_{osc}/64$ (62.5\,кГц). +SPI работал в третьем режиме (высокий уровень CLK, передача информации на падающий +фронт CLK, прием в середине такта -- на возрастающий фронт CLK), регистры: +\begin{verbatim} +SSPCON = 0x32; TRISC = 0xD0; CKE = 0; SSPIE = 1; SMP = 0; +\end{verbatim} + +Для анализа сообщений, отсылаемых фотоаппаратом объективу, SPI переключался в пассивный +режим: +\begin{verbatim} +SSPCON = 0x35; TRISC = 0xD8; CKE = 0; SSPIE = 1; SMP = 0; +\end{verbatim} +Однако, поток данных в обычном режиме работы фотоаппарата довольно велик, а скорость RS--232 +слишком мала, чтобы контроллер успевал за промежуток между посылками отсылать их на~ПК. +Для буферизации посылок использовался массив данных из~95 элементов. Полученные по +SPI--интерфейсу данные буферизовались контроллером в этот массив, а затем, при заполнении +буфера или по команде пользователя, буфер передавался на~ПК. +Однако, и в этом случае оказалось очень много дополнительных команд, не имеющих отношения +к управлению объективом. + +Для подбора команд, вызывающих изменение фокусного расстояния объектива было принято решение +отсылать поочередно объективу ненулевую однобайтную посылку, за которой следовало восемь +нулевых посылок (как оказалось, нулевые посылки используются фотоаппаратом для считывания +информации с объектива). + +Методом последовательного перебора были определены основные управляющие команды. +Временн\'ые интервалы между командами могут быть довольно велики. Если объектив должен +ответить на какой-нибудь запрос, а после запроса никаких посылок не отсылалось, объектив +будет ждать очередных посылок, чтобы выдать запрашиваемые данные. Поэтому стоит +каждую команду завершать последовательностью нулевых посылок. + +\section{Команды EF~200} +Некоторые команды не требуют от объектива ответа, поэтому их можно не завершать нулями, +однако, некоторые запросы подразумевают достаточно длинный ответ, и требуют до восьми +последующих нулевых сообщений. + +Для перехода в ручной режим управления используется команда~{\bf94} или ее эквивалент~{\bf30} +(все команды записываются здесь в десятичной системе). +За этой командой должны следовать одна или две нулевых посылки. +Некоторые команды для изменения фокусного расстояния требуют предварительного +перехода в ручной режим управления. + +Для увеличения фокусного расстояния объектива используются следующие команды +(объектив EF~200, для EF~85 скорости не изменяются). +\begin{description} +\item[5] плавное увеличение фокусного расстояния (если за ней не следует других команд). +\item[37] быстрый переход в~$\infty$, за этой посылкой должны следовать две нулевые. +\end{description} +Для уменьшения фокусного расстояния используются команды +\begin{description} +\item[6] плавное перемещение на отметку~2.5\,м. +\item[22] быстрый переход на отметку~2.5\,м. За этой командой следуют две +нулевых. Эта команда имеет полные эквиваленты: {\bf 38, 70, 86}. +\item[68] поворот привода объектива на заданный угол. Угол задается двумя следующими +байтами (short int, старший байт первый). Узнать текущее угловое положение можно командой~192. +\end{description} +Для останова используется команда~{\bf4}. Таким образом, манипулируя командами~{\bf5/6} +и~{\bf4} можно добиться постепенного изменения фокусного расстояния. Помимо ожидания +для изменения фокусного расстояния на нужную величину после команд~{\bf5} или~{\bf6} +можно отсылать нулевые посылки. + +Кроме этой команды есть следующие информационные команды, чье предназначение +пока не расшифровано (для EF~200, EF~85 см. в сводной таблице): +\begin{description} +\item[31] имеет двухбайтный ответ, оба байта содержали комбинации из единицы и тройки. +\item[79] имеет трехбайтный ответ, являющийся комбинацией единиц и нулей. +\item[95] ведет себя аналогично~{\bf31}. +\item[111] имеет однобайтный ответ~--- единицу. +\item[120] имеет однобайтный ответ~--- восьмерку. +\item[239] имеет однобайтный ответ~--- 224 или 225. +\item[247] однобайтный ответ 240. +\item[250] однобайтный ответ 130 или~128. +\item[251] однобайтный ответ 248. +\item[252] однобайтный ответ (разные числа). +\item[128] ответ из семи или восьми байт, возможно~--- запрос статуса объектива. +\end{description} + +Было обнаружено еще несколько подозрительных запросов, ответом на которые был один +байт с постоянным значением 128 или 192 (при любых манипуляциях с объективом). + + +\subsection{Небольшое дополнение} +команды (EF~85): + +10 --- {\bf инициализация}, без этой команды EF85 не работает. + +194 --- узнать расстояние фокусировки (в метрах). Ответ --- четыре байта, первые два --- текущее расстояние, +вторые два --- предыдущее положение. В паре чисел первое умножаем на 2.5\,м и складываем со вторым (в +сантиметрах). + +192 --- узнать угловое положение лимба (от некоторого условного нуля). Ответ --- два байта (short int, +старший байт первый). + +Управление диафрагмой: два байта число 18 (собственно команда) и байт --- на сколько изменить +текущее состояние диафрагмы (signed char) положительное число для закрытия, отрицательное -- открыть. + + +При небольшом изменении состояния диафрагмы каждая команда 2 или 3 повторяет это изменение. +Плюс объектив входит в режим пошаговой подстройки фокусировки. Выход из этого режима --- команда 8 +(или ее эквиваленты 11, 27, 43, 75). + + +\section{Сводный перечень команд для EF~85} +Расшифровка обозначений столбцов: +\begin{description} +\item[cmd] команда; +\item[N] минимальная длина ответа в байтах; +\item[ans] ответ (в случае изменяющегося ответа --- диапазон); +\item[desc] краткое описание команды. +\end{description} +Команды, чье предназначение не выявлено, имеют пустое поле описания. +Если действие команды аналогично другой команде, в описании пишется эта команда. +Под F подразумевается значение расстояния до объекта, чье изображение +четко сфокусировано. Буква <<о>> в описании означает, что назначение команды +неизвестно, но она приводит к отключению ручного управления~F. +Если в ответах встречаются записи через слеш, значит, в разные моменты времени +появляется то одна, то другая из приведенных команд без видимой зависимости. +\begin{longtable}[c]{||c||c|c| p{0.5\textwidth}||} +\caption{Сводка команд}\\ +\hline\hline +\bf cmd &\bf N &\bf ans &\bf desc\\ +\hline +\hline +\endfirsthead +\caption{(продолжение).}\\ +\hline +\bf cmd &\bf N &\bf ans &\bf desc\\ +\hline +\hline +\endhead +\hline +\endfoot + +0 & 1 & 0 & <<пустышка>> для получения ответа от объектива\\ +1 & 1 & 1 & \\ +\bf 2 & 1 & 2 & повтор предыдущего изменения величины диафрагмы, режим коротких шагов перемещения\\ +3 & 1 & 3 & 2\\ +\bf 4 & 1 & 4 & остановить изменение F\\ +\bf 5 & 1 & 5 & увеличить F\\ +\bf 6 & 1 & 6 & уменьшить F\\ +7 & 1 & 7 & о\\ +\bf 8 & 2 & 255/0, 170 & отмена действия команды 2\\ +9 & 1 & 9 & о\\ +\bf 10 & 1 & 10 & инициализация объектива EF85 (без этой команды он не выходит из спящего режима)\\ +11 & 1 & 11 & 8\\ +12 & 1 & 12 & \\ +13 & 1 & 13 & \\ +14 & 1 & 14 & \\ +15 & 1 & 15 & \\ +16 & 2 & 16, 16 & \\ +17 & 2 & 17, 17 & \\ +\bf 18 & 2 & 18, 18 & управление затвором, вторым байтом (signed char) отсылается степень изменения + диаметра отверстия (положительным значениям соответствует уменьшение диаметра)\\ +19 & 2 & 19, 19 & 18\\ +20 & 2 & 20, 20 & 4\\ +21 & 2 & 21, 21 & 5\\ +22 & 2 & 22, 22 & 6\\ +23 & 2 & 23, 23 & о\\ +24 & 3 & 24, 0/255, 170 & \\ +25 & 2 & 25, 25 & о\\ +26 & 2 & 26, 26 & \\ +27 & 2 & 27, 27 & 8\\ +28 & 2 & 28, 28 & \\ +29 & 2 & 29, 29 & \\ +30 & 2 & 30, 30 & (для EF~200 эквивалент команды 94)\\ +31 & 2 & 31, 31 & \\ +32 & 2 & 32, 32 & \\ +33 & 2 & 33, 33 & \\ +34 & 2 & 34, 34 & \\ +35 & 2 & 35, 35 & \\ +36 & 2 & 36, 36 & 4\\ +37 & 2 & 37, 37 & 5\\ +38 & 2 & 38, 38 & 6\\ +39 & 2 & 39, 39 & о\\ +40 & 3 & 40, 255/0, 170 & \\ +41 & 2 & 41, 41 & о\\ +42 & 2 & 42, 42 & \\ +43 & 2 & 43, 43 & 8\\ +44 & 2 & 44, 44 & \\ +45 & 2 & 45, 45 & \\ +46 & 2 & 46, 46 & \\ +47 & 2 & 47, 47 & \\ +48 & 1 & 48 & \\ +49 & 1 & 49 & \\ +50 & 1 & 50 & \\ +51 & 1 & 51 & \\ +52 & 1 & 52 & \\ +53 & 1 & 53 & \\ +54 & 1 & 54 & \\ +55 & 1 & 55 & \\ +56 & 1 & 56 & \\ +57 & 1 & 57 & \\ +58 & 1 & 58 & \\ +59 & 1 & 59 & \\ +60 & 1 & 60 & \\ +61 & 1 & 61 & \\ +62 & 1 & 62 & \\ +63 & 1 & 63 & \\ +64 & 3 & 64, 64, 64 & \\ +65 & 3 & 65, 65, 65 & \\ +66 & 3 & 66, 66, 66 & \\ +67 & 3 & 67, 67, 67 & \\ +68 & 3 & 68, 68, 68 & переместить объектив на заданное кол-во шагов (2 байта, int16, hi-low)\\ +69 & 3 & 69, 69, 69 & 5\\ +70 & 3 & 70, 70, 70 & 6\\ +71 & 3 & 71, 71, 71 & о\\ +72 & 4 & 72, 72, 255/0, 170 & \\ +73 & 3 & 73, 73, 73 & о\\ +74 & 3 & 74, 74, 170 & \\ +75 & 3 & 75, 75, 75 & 8\\ +76 & 3 & 76, 76, 76 & \\ +77 & 3 & 77, 77, 77 & \\ +78 & 3 & 78, 78, 78 & (для EF~200 эквивалент команды 94)\\ +79 & 3 & 79, 79, 79 & \\ +80 & 2 & 80, 80 & \\ +81 & 2 & 81, 81 & \\ +82 & 2 & 82, 82 & \\ +83 & 2 & 83, 83 & \\ +84 & 2 & 84, 84 & 4\\ +85 & 2 & 85, 85 & 5\\ +86 & 2 & 86, 86 & 6\\ +87 & 2 & 87, 87 & о\\ +88 & 3 & 88, 255/0, 170 & \\ +89 & 2 & 89, 89 & о\\ +90 & 2 & 90, 170 & \\ +91 & 2 & 91, 91 & \\ +92 & 2 & 92, 92 & \\ +93 & 2 & 93, 93 & \\ +\bf 94 & 2 & 94, 94 & включить ручное управление F\\ +95 & 2 & 95, 95 & \\ +96 & 1 & 96 & \\ +97 & 1 & 97 & \\ +98 & 1 & 98 & \\ +99 & 1 & 99 & \\ +100 & 1 & 100 & \\ +101 & 1 & 101 & \\ +102 & 1 & 102 & \\ +103 & 1 & 103 & \\ +104 & 1 & 240 & \\ +105 & 1 & 35 & \\ +106 & 2 & 35, 253 & \\ +107 & 2 & 232, 103 $\div$ 215, 185& \\ +108 & 2 & 108, 236 $\div$ 112, 0 & \\ +109 & 2 & 220, 80 $\div$ 103, 56 & \\ +110 & 2 & 112, 108 $\div$ 113, 62 & \\ +111 & 1 & 0/16 & \\ +112 & 1 & 112 & \\ +113 & 1 & 113 & \\ +114 & 1 & 114 & \\ +115 & 1 & 115 & \\ +116 & 1 & 116 & \\ +117 & 1 & 117 & \\ +118 & 1 & 118 & \\ +119 & 1 & 119 & \\ +120 & 1 & 120 & \\ +121 & 1 & 121 & \\ +122 & 1 & 122 & \\ +123 & 1 & 123 & \\ +124 & 1 & 124 & \\ +125 & 1 & 125 & \\ +126 & 1 & 126 & \\ +127 & 1 & 127 & \\ +128 & 6 & 129, 239, 0, 85, 0, 85 & модель объектива ?\\ +129 & 1 & 129 & \\ +130 & 1 & 130 & \\ +131 & 1 & 131 & \\ +132 & 1 & 132 & \\ +133 & 1 & 133 & \\ +134 & 1 & 134 & \\ +135 & 1 & 135 & \\ +136 & 1 & 136 & \\ +137 & 1 & 137 & \\ +138 & 1 & 138 & \\ +139 & 1 & 139 & \\ +140 & 1 & 140 & \\ +141 & 1 & 141 & \\ +142 & 1 & 142 & \\ +143 & 1 & 143 & \\ +\bf 144 & 2 & 0/32, $X$ & старший бит $X$ --- значение переключателя <> (нулю + соответствует AF)\\ +145 & 1 & 145 & \\ +146 & 1 & 146 & \\ +147 & 1 & 147 & \\ +148 & 1 & 255 & \\ +149 & 1 & 149 & \\ +150 & 1 & 150 & \\ +151 & 1 & 151 & \\ +152 & 1 & 152 & \\ +153 & 1 & 153 & \\ +154 & 1 & 154 & \\ +155 & 1 & 155 & \\ +156 & 1 & 156 & \\ +157 & 1 & 157 & \\ +158 & 1 & 158 & \\ +159 & 1 & 159 & \\ +160 & 2 & 0, 85 & \\ +161 & 1 & 161 & \\ +162 & 1 & 162 & \\ +163 & 1 & 163 & \\ +164 & 1 & 164 & \\ +165 & 1 & 165 & \\ +166 & 1 & 166 & \\ +167 & 1 & 167 & \\ +168 & 1 & 168 & \\ +169 & 1 & 169 & \\ +170 & 1 & 170 & \\ +171 & 1 & 171 & \\ +172 & 1 & 172 & \\ +173 & 1 & 173 & \\ +174 & 1 & 174 & \\ +175 & 1 & 175 & \\ +176 & 3 & 13, 13, 72 & \\ +177 & 2 & 91, 92 & \\ +178 & 3 & 96, 2, 71 & \\ +179 & 2 & 104, 92 & \\ +180 & 1 & 180 & \\ +181 & 1 & 181 & \\ +182 & 1 & 182 & \\ +183 & 1 & 183 & \\ +184 & 1 & 184 & \\ +185 & 1 & 185 & \\ +186 & 1 & 186 & \\ +187 & 1 & 187 & \\ +188 & 1 & 188 & \\ +189 & 1 & 189 & \\ +190 & 1 & 190 & \\ +191 & 1 & 191 & \\ +\bf 192 & 2 & short int & угловое положение лимба F, первый байт --- старший, нуль относительный\\ +193 & 1 & 193 & \\ +\bf 194 & 4 & $X_1, X_2, Y_1, Y_2$ & значение F в метрах; $X$~-- текущее F, $Y$~-- предыдущее F; + $F(\text{метр}) = 2.5\cdot X_1+X_2/100$ \\ +195 & 1 & 195 & \\ +196 & 2 & 0, 9 $\div$ 10, 1 & \\ +197 & 1 & 197 & \\ +198 & 1 & 198 & \\ +199 & 1 & 199 & \\ +200 & 1 & 200 & \\ +201 & 1 & 201 & \\ +202 & 1 & 202 & \\ +203 & 1 & 203 & \\ +204 & 1 & 204 & \\ +205 & 1 & 205 & \\ +206 & 1 & 206 & \\ +207 & 1 & 207 & \\ +208 & 1 & 208 & \\ +209 & 1 & 209 & \\ +210 & 1 & 210 & \\ +211 & 1 & 211 & \\ +212 & 1 & 212 & \\ +213 & 1 & 213 & \\ +214 & 1 & 214 & \\ +215 & 1 & 215 & \\ +216 & 1 & 216 & \\ +217 & 1 & 217 & \\ +218 & 1 & 218 & \\ +219 & 1 & 219 & \\ +220 & 1 & 220 & \\ +221 & 1 & 221 & \\ +222 & 1 & 222 & \\ +223 & 1 & 223 & \\ +224 & 2 & 61, 186 $\div$ 61, 172 & \\ +225 & 1 & 225 & \\ +226 & 1 & 226 & \\ +227 & 1 & 227 & \\ +228 & 2 & 30, 84 & \\ +229 & 1 & 229 & \\ +230 & 1 & 230 & \\ +231 & 1 & 231 & \\ +232 & 2 & 163, 203 $\div$ 162, 105 & \\ +233 & 1 & 233 & \\ +234 & 2 & 157, 166 $\div$ 163, 205 & \\ +235 & 1 & 235 & \\ +236 & 1 & 236 & \\ +237 & 1 & 237 & \\ +238 & 1 & 238 & \\ +239 & 1 & 239 & \\ +240 & 1 & 10 & \\ +241 & 1 & 241 & \\ +242 & 1 & 242 & \\ +243 & 1 & 243 & \\ +244 & 1 & 244 & \\ +245 & 1 & 245 & \\ +246 & 1 & 246 & \\ +247 & 1 & 247 & \\ +248 & 1 & 185 $\div$ 188 & \\ +249 & 1 & 3 $\div$ 7 & \\ +250 & 1 & 192 $\div$ 194 & \\ +251 & 1 & 251 & \\ +252 & 1 & 198 $\div$ 201 & \\ +253 & 1 & 0 & \\ +254 & 1 & 207 $\div$ 208 & \\ +255 & 1 & 255 & \\ +\hline\hline +\end{longtable} +Команды можно условно разделить на две половины: если старший бит команды равен нулю, объектив +выполняет определенные действия. Когда старший бит команды равен единицы, у объектива запрашиваются +определенные данные. + +Команды изменения F аналогичны (за исключением разрядности ответа). Младшие 4~байта принимают +значения 0100 (стоп), 0101 (F$+$), 0110 (F$-$), самый старший бит --- обязательно 0. +Биты $4\div6$ принимают любые значения, кроме 110, 011 и 111. +\end{document} + diff --git a/pins.pdf b/pins.pdf new file mode 100644 index 0000000..b9707c6 Binary files /dev/null and b/pins.pdf differ