Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <pic16f870.h>
- #include "main.h"
- //#define CLRWDT _asm clrwdt _endasm;
- typedef unsigned int word;
- word at 0x2007 CONFIG = 0x3F72; // для WDT: 0x3F76
- unsigned char pos, // текущая позиция шаговика
- cmd, // команда или данные с ПК
- voltage, // рабочее напряжение
- mC_addr, // физ. адрес контроллера (константа, устанавливается функцией init)
- // test_flag, // тестируем?
- terminal_stops_motor, // концевики в режиме останова двигателя
- terminal_flag, // флаг обработки концевиков
- isstep, // нагрузка - шаговый двигатель
- block, // удерживать ли ШД при окончании движения, и каким напряжением это делать
- TMR_H, TMR_L, // начальные значения счетчика 1го таймера
- d_H, d_L, // данные для функции getword
- mode_mask, stop_mask, stop_mask2, // маски для режима работы концевиков/останавливающих концевиков
- stop_bits, stop_bits2, // выражения для проверки на останов двигателей
- async_msgs; // разрешены ли асинхронные сообщения?
- char dir_glob = 1, dir_before_term = 0; // направление вращения (глобальное / до концевика)
- char term_send = 1; // флаг отсылки сообщения о концевиках
- unsigned int steps = 0, // кол-во шагов, на которое надо повернуть шаговик
- total_steps = 0; // кол-во пройденных шагов
- const unsigned char phase[] = {0x04, 0x00, 0x01, 0x02, 0x06, 0x0A, 0x09, 0x08}; // управление фазами ШД
- //{0x08, 0x00, 0x02, 0x0A, 0x08, 0x00, 0x02, 0x0A};
- const unsigned char dpmconf[] = {0xFC, 0x00, //1л режимы работы ДПМ (по порядку команд), первое число - AND, второе - OR
- 0xFC, 0x02, // 1п
- 0xF3, 0x00, // 2л
- 0xF3, 0x08, // 2п
- 0xF0, 0x00, // 1л2л
- 0xF0, 0x08, // 1л2п
- 0xF0, 0x02, // 1п2л
- 0xF0, 0x0A, // 1п2п
- 0xFC, 0x01, // 1стоп
- 0xF3, 0x04, // 2стоп
- 0xF0, 0x05 // 12стоп
- }; //FC - 1й, F3 - 2й, F0 - оба
- void set_voltage(unsigned char V){ // установка питающих напряжений
- unsigned char tmp = PORTC;
- tmp &= 0xF8; // сбрасываем младшие 3 бита
- tmp |= V;
- PORTC = tmp; // устанавливаем напряжение
- }
- void change_voltage(unsigned char V){
- unsigned char tmp = PORTC;
- voltage = V;
- if((tmp & 0x07) != 0){// напряжение меняется при работающем механизме
- tmp &= 0xF8; // сбрасываем младшие 3 бита
- tmp |= V;
- PORTC = tmp; // устанавливаем напряжение
- }
- }
- void step(char dir){ // управление шаговым двигателем
- unsigned char tmp = PORTA & 0xF0;
- pos+=dir; pos &= 0x07; // выбираем следующее значение фазовых напряжений
- PORTA = tmp | phase[pos]; // устанавливаем соотв. напряжение
- total_steps ++; // увеличиваем (уменьшаем) счетчик от концевика
- }
- void dpm(char dir){
- unsigned char tmp = PORTA;
- tmp &= dpmconf[dir]; // установка
- PORTA = tmp | dpmconf[dir+1]; // режима
- if(dir != 20) set_voltage(voltage); // подаем напряжение
- else set_voltage(block); // сбрасываем напряжение
- }
- void send9bit(unsigned char something){
- unsigned char tmp;
- something &= 0x1F; // сброс старших трех бит (там будет адрес)
- tmp = mC_addr | something;
- TXEN = 1; // готов к передаче
- // while(!TRMT){}; // подождать, пока не освободится буфер передачи
- TX9D = 0; // 0 - передает контроллер
- TXREG = tmp; // послать команду
- }
- unsigned char get9bit(){
- unsigned char err1, err2, flag9bit, tmp;
- // CLRWDT
- 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; // (1100000) - 0..5 биты как выходы
- INTCON = 0; // отключить все прерывания
- // PIE1: | PSPIE | ADIE | RCIE | TXIE | N/A | CCP1IE | TMR2IE | TMR1IE |
- PIE1 = 0x21; // (00100001): enable USART(in) & TIMER1 interrupt
- // 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 &= 0xF8; // (11111000) - отключение напряжений
- PORTC = 0; // без напряжения
- PORTA = 0xF; // (00001111)
- // получение адреса
- mC_addr = PORTB; // физический адрес устройства
- mC_addr &= 0xE0; // выделение физического адреса
- // инициализация переменных
- pos = 0;
- // test_flag = 0;
- terminal_flag = 0;
- terminal_stops_motor = 0;
- block = 0;
- isstep = 0;
- TMR_H = 0;
- TMR_L = 0;
- voltage = NINE;
- async_msgs = 0;
- timer1set(ON);
- }
- void timer1set(unsigned char on_off){ // установка таймера
- T1CON = 0; // выключить таймер
- TMR1IF = 0; // сбросить флаг прерывания
- TMR1IE = on_off; // разр/запр прерывание
- // CLRWDT
- if(on_off == OFF) return; // отключили таймер и вышли
- TMR1H = TMR_H; TMR1L = TMR_L; // установить счетчики
- // T1CON: | - | - | T1CPS1 | T1CPS0 | T1OSCEN | T1SYNC | TMR1CS | TMR1ON |
- T1CON = 0x31; // (00110001) - включить таймер 1, предделитель на 1/8 (250 кГц)
- }
- void timer1int(){ // обработка прерываний первого таймера
- unsigned char term_reg, stop1, stop2; // концевики для останова
- // CLRWDT // очистить watchdog
- timer1set(ON); // восстановить таймер
- // if(test_flag) send9bit(TEST); // на каждое прерывание посылать тестовое сообщение
- term_reg = PORTB;
- term_reg &= 0x1F; // выделяем концевики
- stop1 = term_reg & stop_mask;
- stop2 = term_reg & stop_mask2;
- if(steps != 0 && isstep){ // если надо поворачивать шаговик,
- if(terminal_stops_motor && (stop1 != stop_bits) &&
- term_send){// концевики RB0, RB4
- steps = 1; // останов шаговика (далее steps еще уменьшится на 1)
- dir_before_term = dir_glob;
- dir_glob = -dir_glob; // и сменить направление вращения
- }
- step(dir_glob); // повернуть двигатель
- steps--; // уменьшаем кол-во оставшихся шагов
- if(steps == 0) // устанавливаем напряжение удержания 9В
- set_voltage(block);
- }
- // проверим концевики
- // обработка событий срабатывания концевика происходит только один раз
- // следующая обработка - только при деактивации концевиков
- if((term_reg != mode_mask) && terminal_flag){ // сработал(и) концевик(и)
- if(term_send){ // обрабатываем?
- if(async_msgs){ // разрешена отправка асинхронных сообщений
- send9bit(TERMINALS); // посылаем извещение о срабатывании концевика
- send9bit(term_reg); // и сообщаем код концевиков
- }
- term_send = 0;
- if(terminal_stops_motor && !isstep){ // концевики останавливают двигатели
- if(stop1 != stop_bits)// концевики, останавливающие дв. 1
- dpm(16);
- if(stop2 != stop_bits2)// -//- двигатель 2
- dpm(18);
- }
- }
- }
- else{ // сошли с концевика
- term_send = 1; // разрешаем отсылку/обработку сообщений о срабатывании концевиков
- }
- }
- void rot_step(char dir){ // движение ШД на заданное кол-во шагов
- int newsteps;
- if(!getword()) return; // возврат по ошибке получения кол-ва шагов
- if(term_send == 0){ // сидим на концевике, сигнал уже обработан
- if(dir == dir_before_term){ // попытка вращать в сторону концевика сразу после наезда
- term_send = 1; // при следующем удобном случае отошлем сигнал о концевике
- return;
- }
- total_steps = 0; // сбрасываем кол-во шагов
- }
- else dir_before_term = 0; // сбрасываем запрещенное направление
- newsteps = (d_H << 8) | d_L; // количество шагов
- if (dir != dir_glob){ // добавить шаги в обратном направлении
- if(steps < newsteps){ // точка назначения в противоположном направлении
- steps = newsteps - steps;
- dir_glob = dir; // устанавливаем новое направление вращения
- }
- else
- steps -= newsteps; // иначе просто вычитаем нужное кол-во шагов
- }
- else steps += newsteps; // добавляем шаги в прямом направлении
- set_voltage(voltage); // устанавливаем раб. напряжение (м.б. выход из удержания - 9В)
- // timer1set(ON); // включаем таймер
- }
- void tot_steps(){ // отсылаем текущее положение ШД
- unsigned char ts_h, ts_l;
- if(!isstep){
- send9bit(ERR_CMD);
- return;
- }
- ts_h = total_steps >> 8;
- ts_l = total_steps & 0xFF;
- sendword(ts_h, ts_l);
- }
- void get_term_method(){ // получение режима работы концевиков
- /* Режим работы передается в двух байтах по следующей схеме:
- |TS| A | stop_mask ||TF| B | mode_mask |
- H/| 7| 6 5| 4 3 2 1 0 ||7 | 6 5| 4 3 2 1 0 |/L
- TS - terminal_stop_motor (1-концевик останавливает двигатель)
- TF - terminal_flag (1-концевики обрабатываются)
- mode_mask - уровень сигнала с незамкнутых концевиков
- stop_mask - 1-данный концевик останавливает ШД или ДПМ1
- AB-stop_mask2 - 1-данный концевик останавливает ДПМ2
- */
- if(!getword()) return;
- terminal_stops_motor = d_H & 0x80;
- terminal_flag = d_L & 0x80 | terminal_stops_motor; // во избежании ошибок
- stop_mask = d_H & 0x1F;
- stop_mask2 = ((d_H & 60) << 2) | (d_L & 60);
- mode_mask = d_L & 0x1F;
- stop_bits = mode_mask & stop_mask;
- stop_bits2 = mode_mask & stop_mask2;
- }
- void get_flags(){
- if(!getword()) return;
- /* Флаги передаются в двух байтах по схеме:
- | RESERVED u_blk | RESERVED async_msgs |
- H/| 765432 1 0 | 7654321 0 |/L
- async_msgs - асинхронные сообщения (0 - запретить, 1 - разрешить)
- u_blk - напряжение удержания (00 - нет, 01 - 9, 10 - 12, 11 - 24)
- */
- async_msgs = d_L & 1;
- block = (8 >> (d_H & 3)) & 7;
- }
- void on_interrupt() __interrupt 0{ // обработка прерываний
- if(RCIF == 1){ // поступило прерывание от USART
- if(get9bit() != OK) return;
- switch(cmd){
- case INIT: init(); break;
- case SET09V: change_voltage(NINE); break;
- case SET12V: change_voltage(TWELVE); break;
- case SET24V: change_voltage(TWENTYFOUR); break;
- case STEP_LEFT: step(LEFT); break;
- case STEP_RIGHT: step(RIGHT); break;
- case DPM1L: dpm(0); break;
- case DPM1R: dpm(2); break;
- case DPM2L: dpm(4); break;
- case DPM2R: dpm(6); break;
- case DPM1L2L: dpm(8); break;
- case DPM1L2R: dpm(10); break;
- case DPM1R2L: dpm(12); break;
- case DPM1R2R: dpm(14); break;
- case DPM1_STOP: dpm(16); break;
- case DPM2_STOP: dpm(18); break;
- case ISSTEP: isstep = 1; break;
- case ISNTSTEP: isstep = 0; break;
- case STEP_L_NUM: rot_step(LEFT); break;
- case STEP_R_NUM: rot_step(RIGHT); break;
- case STEP_STOP: steps = 0; dpm(20); break;
- case TOTAL_STEPS: tot_steps(); break;
- case SET_TIMER: if(getword()){
- TMR_H = d_H; TMR_L = d_L;
- timer1set(ON);}
- else send9bit(ERR_CMD);
- break;
- case STOP_TIMER: timer1set(OFF); break;
- case TMR_SETTINGS: sendword(TMR_H, TMR_L); break;
- // case TEST: test_flag = !test_flag; break;
- case TERM_METHOD: get_term_method(); break;
- case RESERVED_FLAGS: get_flags(); break;
- case TERMINALS: send9bit(PORTB);
- //default: send9bit(ERR_CMD); break;
- }
- }
- if(TMR1IF == 1) // поступило прерывание от таймера
- timer1int(); // обработать прерывание
- }
- void main(){ // основной цикл
- init();
- while(1){};//CLRWDT};
- }
Advertisement
Add Comment
Please, Sign In to add comment