Guest User

Eddy_Em

a guest
Oct 31st, 2011
208
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 16.54 KB | None | 0 0
  1. #include    <pic16f870.h>
  2. #include "main.h"
  3. //#define CLRWDT    _asm clrwdt _endasm;
  4. typedef unsigned int word;
  5. word at 0x2007 CONFIG = 0x3F72; // для WDT: 0x3F76
  6. unsigned char pos, // текущая позиция шаговика
  7.     cmd, // команда или данные с ПК
  8.     voltage, // рабочее напряжение
  9.     mC_addr, // физ. адрес контроллера (константа, устанавливается функцией init)
  10. //  test_flag, // тестируем?
  11.     terminal_stops_motor,  // концевики в режиме останова двигателя
  12.     terminal_flag, // флаг обработки концевиков
  13.     isstep, // нагрузка - шаговый двигатель
  14.     block, // удерживать ли ШД при окончании движения, и каким напряжением это делать
  15.     TMR_H, TMR_L, // начальные значения счетчика 1го таймера
  16.     d_H, d_L, // данные для функции getword
  17.     mode_mask, stop_mask, stop_mask2, // маски для режима работы концевиков/останавливающих концевиков
  18.     stop_bits, stop_bits2, // выражения для проверки на останов двигателей
  19.     async_msgs; // разрешены ли асинхронные сообщения?
  20. char dir_glob = 1, dir_before_term = 0; // направление вращения (глобальное / до концевика)
  21. char term_send = 1; // флаг отсылки сообщения о концевиках
  22. unsigned int steps = 0, // кол-во шагов, на которое надо повернуть шаговик
  23.     total_steps = 0; // кол-во пройденных шагов
  24.  
  25. const unsigned char phase[] = {0x04, 0x00, 0x01, 0x02, 0x06, 0x0A, 0x09, 0x08}; // управление фазами ШД
  26. //{0x08, 0x00, 0x02, 0x0A, 0x08, 0x00, 0x02, 0x0A};
  27.  
  28. const unsigned char dpmconf[] = {0xFC, 0x00,  //1л режимы работы ДПМ (по порядку команд), первое число - AND, второе - OR
  29.     0xFC, 0x02, // 1п
  30.     0xF3, 0x00, // 2л
  31.     0xF3, 0x08, // 2п
  32.     0xF0, 0x00, // 1л2л
  33.     0xF0, 0x08, // 1л2п
  34.     0xF0, 0x02, // 1п2л
  35.     0xF0, 0x0A, // 1п2п
  36.     0xFC, 0x01, // 1стоп
  37.     0xF3, 0x04, // 2стоп
  38.     0xF0, 0x05 // 12стоп
  39.     }; //FC - 1й, F3 - 2й, F0 - оба
  40.  
  41. void set_voltage(unsigned char V){  // установка питающих напряжений
  42.     unsigned char tmp = PORTC;
  43.     tmp &= 0xF8; // сбрасываем младшие 3 бита
  44.     tmp |= V;  
  45.     PORTC = tmp; // устанавливаем напряжение
  46. }  
  47.  
  48. void change_voltage(unsigned char V){
  49.     unsigned char tmp = PORTC;
  50.     voltage = V;
  51.     if((tmp & 0x07) != 0){// напряжение меняется при работающем механизме
  52.         tmp &= 0xF8; // сбрасываем младшие 3 бита
  53.         tmp |= V;  
  54.         PORTC = tmp; // устанавливаем напряжение
  55.     }
  56. }
  57.  
  58. void step(char dir){ // управление шаговым двигателем
  59.     unsigned char tmp = PORTA & 0xF0;
  60.     pos+=dir; pos &= 0x07; // выбираем следующее значение фазовых напряжений
  61.     PORTA = tmp | phase[pos]; // устанавливаем соотв. напряжение
  62.     total_steps ++; // увеличиваем (уменьшаем) счетчик от концевика
  63. }
  64.  
  65. void dpm(char dir){
  66.     unsigned char tmp = PORTA;
  67.     tmp &= dpmconf[dir]; // установка
  68.     PORTA = tmp | dpmconf[dir+1]; //   режима
  69.     if(dir != 20) set_voltage(voltage); // подаем напряжение
  70.     else set_voltage(block); // сбрасываем напряжение
  71. }
  72.  
  73. void send9bit(unsigned char something){
  74.     unsigned char tmp;
  75.     something &= 0x1F; // сброс старших трех бит (там будет адрес)
  76.     tmp = mC_addr | something;
  77.     TXEN = 1; // готов к передаче
  78. //  while(!TRMT){}; // подождать, пока не освободится буфер передачи
  79.     TX9D = 0; // 0 - передает контроллер
  80.     TXREG = tmp;    // послать команду
  81. }
  82.  
  83. unsigned char get9bit(){
  84.     unsigned char err1, err2, flag9bit, tmp;
  85. //  CLRWDT
  86.     while(!RCIF);
  87.     flag9bit = RX9D;
  88.     err1 = FERR; err2 = OERR; // считать 9-й бит и ошибки
  89.     cmd = RCREG; // очистить буфер данных
  90.     RX9D = 0;
  91.     if(err1 == 1){
  92.         send9bit(NO_STOP_BIT); // не обнаружен стоповый бит
  93.         return NO_STOP_BIT;
  94.     }
  95.     if(err2 == 1){
  96.         send9bit(STACK_OVERFLOW); // переполнение приемных регистров
  97.         CREN = 0; CREN = 1; // сбросить флаг ошибки
  98.         return STACK_OVERFLOW;
  99.     }
  100.     if(flag9bit) return TWOBYTE; // данные - часть двухбайтной посылки (неизвестно еще чьей :) )
  101.     tmp = cmd & 0xE0; // выделение адреса из команды
  102.     cmd &= 0x1F; // обнуление адресных битов
  103.     if(tmp != mC_addr) return ERR_CMD; // если адресован чужому
  104.     send9bit(cmd); // Эхо принятой команды
  105.     return OK;
  106. }
  107.  
  108. void sendword(unsigned char data_H, unsigned char data_L){
  109.     RCIE = 0; // disable USART in interrupt
  110.     TMR1IE = 0;
  111.     TXEN = 1;
  112.     TX9D = 1;
  113.     TXREG = data_H;
  114.     while(!TRMT);
  115.     TXEN = 1;
  116.     TX9D = 1;
  117.     TXREG = data_L;
  118.     RCIE = 1;
  119.     TMR1IE = 1;
  120. }
  121.  
  122.  
  123. unsigned char getword(){
  124.     unsigned char ret = 0;
  125.     RCIE = 0; // disable USART in interrupt
  126.     TMR1IE = 0;
  127.     if(ten_times_read()){
  128.         d_H = cmd;
  129.         if(ten_times_read()){
  130.             d_L = cmd;
  131.             ret = 1;}} // если оба байта считали правильно
  132.     TMR1IE = 1;
  133.     RCIE = 1; // enable USART in interrupt
  134.     return ret;
  135. }
  136.  
  137. unsigned char ten_times_read(){ // 10 попыток чтения для двухбайтного приема
  138.     unsigned char i=0;
  139.     do i++;
  140.     while(get9bit() != TWOBYTE && i < 10);
  141.     if(i > 9){send9bit(ERR_CMD); return 0;}
  142.     send9bit(OK);
  143.     return 1;
  144. }
  145.  
  146. void init(){ // инициализация
  147. // Настройка USART'a
  148. // TXSTA: | CSRC | TX9 | TXEN | SYNC | N/A | BRGH | TRMT | TX9D |
  149.     TXSTA = 0x66; // (11000110): master, 9-ти битный ввод/вывод, async, hi-speed, ready
  150. // SPBRG - скорость передачи
  151.     SPBRG = 25; // 9.6 кб/с
  152. // RCSTA: | SPEN | RX9 | SREN | CREN | ADDEN | FERR | OERR | RX9D |
  153.     RCSTA = 0xD0; // ( 11010000): enable, 9bit, continuous mode
  154. // настройка портов:
  155.     PORTA = 0; // 6-ти битный аналогово/цифровой порт (0..5 биты)
  156. // ADCON1: | ADFM | N/A | N/A | N/A | PCFG3 | PCFG2 | PCFG1 | PCFG0 |
  157.     ADCON1 = 0x06; // Аналогово/цифровой порт работает в полностью цифровом режиме
  158.     TRISA = 0; // направление порт А (1-вход, 0-выход)
  159.     TRISB = 0xff; //           --/ B /--
  160. // OPTION_REG: | !RBPU | INTEDG | TOCS | TOSE | PSA | PS2 | PS1 | PS0 |
  161.     OPTION_REG = 0x7f; /* (01111111) 0 - подключение подтяжек на порт B (уст. лог. 1),
  162.                 прерывание по нарастающему фронту RB0,
  163.                 таймер 0 работает по сигналу с RA4
  164.                 таймер 0 увеличивается при спаде сигнала на RA4
  165.                 предделитель подключен к сторожевому таймеру
  166.                 режим prescaler:  1:128 */
  167.     TRISC = 0xC0; // (1100000) - 0..5 биты как выходы
  168.     INTCON = 0; // отключить все прерывания
  169. // PIE1: | PSPIE | ADIE | RCIE | TXIE | N/A | CCP1IE | TMR2IE | TMR1IE |
  170.     PIE1 = 0x21; // (00100001): enable USART(in) & TIMER1 interrupt
  171. // PIE2: все N/A, кроме EEIE (PIE2.4)
  172.     PIE2 = 0; //                & disable other int.s
  173.     PORTB = 0;
  174. // INTCON: | GIE | PEIE | T0IE | INTE | RBIE | T0IF | INTF | RBIF |
  175.     INTCON = 0xC0; // (1100000) - включить глобальные прерывания, прерывания по периферии
  176. //PORTC &= 0xF8; // (11111000) - отключение напряжений
  177.     PORTC = 0; // без напряжения
  178.     PORTA = 0xF; // (00001111)
  179. // получение адреса
  180.     mC_addr = PORTB; // физический адрес устройства
  181.     mC_addr &= 0xE0; // выделение физического адреса
  182. // инициализация переменных
  183.     pos = 0;
  184. //  test_flag = 0;
  185.     terminal_flag = 0;
  186.     terminal_stops_motor = 0;
  187.     block = 0;
  188.     isstep = 0;
  189.     TMR_H = 0;
  190.     TMR_L = 0;
  191.     voltage = NINE;
  192.     async_msgs = 0;
  193.     timer1set(ON);
  194. }
  195.  
  196. void timer1set(unsigned char on_off){ // установка таймера
  197.     T1CON = 0; // выключить таймер
  198.     TMR1IF = 0; // сбросить флаг прерывания
  199.     TMR1IE = on_off; // разр/запр прерывание
  200. //  CLRWDT
  201.     if(on_off == OFF) return; // отключили таймер и вышли
  202.     TMR1H = TMR_H; TMR1L = TMR_L;  // установить счетчики
  203. // T1CON: | - | - | T1CPS1 | T1CPS0 | T1OSCEN | T1SYNC | TMR1CS | TMR1ON |
  204.     T1CON = 0x31; // (00110001) - включить таймер 1, предделитель на 1/8 (250 кГц)
  205. }
  206.  
  207. void timer1int(){ // обработка прерываний первого таймера
  208.     unsigned char term_reg, stop1, stop2; // концевики для останова
  209. //  CLRWDT // очистить watchdog
  210.     timer1set(ON); // восстановить таймер
  211. //  if(test_flag) send9bit(TEST); // на каждое прерывание посылать тестовое сообщение
  212.     term_reg = PORTB;
  213.     term_reg &= 0x1F; // выделяем концевики
  214.     stop1 = term_reg & stop_mask;
  215.     stop2 = term_reg & stop_mask2;
  216.     if(steps != 0 && isstep){ // если надо поворачивать шаговик,
  217.         if(terminal_stops_motor && (stop1 != stop_bits) &&
  218.                 term_send){// концевики RB0, RB4
  219.             steps = 1; //  останов шаговика (далее steps еще уменьшится на 1)
  220.             dir_before_term = dir_glob;
  221.             dir_glob = -dir_glob; // и сменить направление вращения
  222.         }
  223.         step(dir_glob); // повернуть двигатель
  224.         steps--; // уменьшаем кол-во оставшихся шагов
  225.         if(steps == 0) // устанавливаем напряжение удержания 9В
  226.             set_voltage(block);
  227.     }
  228.     // проверим концевики
  229.     // обработка событий срабатывания концевика происходит только один раз
  230.     // следующая обработка - только при деактивации концевиков
  231.     if((term_reg != mode_mask) && terminal_flag){ // сработал(и) концевик(и)
  232.         if(term_send){ // обрабатываем?
  233.             if(async_msgs){ // разрешена отправка асинхронных сообщений
  234.                 send9bit(TERMINALS); // посылаем извещение о срабатывании концевика
  235.                 send9bit(term_reg); // и сообщаем код концевиков
  236.             }
  237.             term_send = 0;
  238.             if(terminal_stops_motor && !isstep){ // концевики останавливают двигатели
  239.                 if(stop1 != stop_bits)// концевики, останавливающие дв. 1
  240.                     dpm(16);
  241.                 if(stop2 != stop_bits2)// -//- двигатель 2
  242.                     dpm(18);
  243.             }
  244.         }
  245.     }
  246.     else{ // сошли с концевика
  247.         term_send = 1; // разрешаем отсылку/обработку сообщений о срабатывании концевиков
  248.     }
  249. }
  250.  
  251. void rot_step(char dir){ // движение ШД на заданное кол-во шагов
  252.     int newsteps;
  253.     if(!getword()) return; // возврат по ошибке получения кол-ва шагов
  254.     if(term_send == 0){ // сидим на концевике, сигнал уже обработан
  255.         if(dir == dir_before_term){ // попытка вращать в сторону концевика сразу после наезда
  256.             term_send = 1; // при следующем удобном случае отошлем сигнал о концевике
  257.             return;
  258.         }
  259.         total_steps = 0; // сбрасываем кол-во шагов
  260.     }
  261.     else dir_before_term = 0; // сбрасываем запрещенное направление
  262.     newsteps = (d_H << 8) | d_L; // количество шагов
  263.     if (dir != dir_glob){ // добавить шаги в обратном направлении
  264.         if(steps < newsteps){ // точка назначения в противоположном направлении
  265.             steps = newsteps - steps;
  266.             dir_glob = dir; // устанавливаем новое направление вращения
  267.         }
  268.         else
  269.             steps -= newsteps; // иначе просто вычитаем нужное кол-во шагов
  270.     }
  271.     else steps += newsteps; // добавляем шаги в прямом направлении
  272.     set_voltage(voltage); // устанавливаем раб. напряжение (м.б. выход из удержания - 9В)
  273. //  timer1set(ON); // включаем таймер
  274. }
  275.  
  276. void tot_steps(){ // отсылаем текущее положение ШД
  277.     unsigned char ts_h, ts_l;
  278.     if(!isstep){
  279.         send9bit(ERR_CMD);
  280.         return;
  281.     }
  282.     ts_h = total_steps >> 8;
  283.     ts_l = total_steps & 0xFF;
  284.     sendword(ts_h, ts_l);
  285. }
  286.  
  287. void get_term_method(){ // получение режима работы концевиков
  288. /* Режим работы передается в двух байтах по следующей схеме:
  289.       |TS|  A | stop_mask ||TF|  B | mode_mask |
  290.     H/| 7| 6 5| 4 3 2 1 0 ||7 | 6 5| 4 3 2 1 0 |/L
  291.     TS - terminal_stop_motor (1-концевик останавливает двигатель)
  292.     TF - terminal_flag (1-концевики обрабатываются)
  293.     mode_mask - уровень сигнала с незамкнутых концевиков
  294.     stop_mask - 1-данный концевик останавливает ШД или ДПМ1
  295.     AB-stop_mask2 - 1-данный концевик останавливает ДПМ2
  296. */
  297.     if(!getword()) return;
  298.     terminal_stops_motor = d_H & 0x80;
  299.     terminal_flag = d_L & 0x80 | terminal_stops_motor; // во избежании ошибок
  300.     stop_mask = d_H & 0x1F;
  301.     stop_mask2 = ((d_H & 60) << 2) | (d_L & 60);
  302.     mode_mask = d_L & 0x1F;
  303.     stop_bits = mode_mask & stop_mask;
  304.     stop_bits2 = mode_mask & stop_mask2;
  305. }
  306.  
  307. void get_flags(){
  308.     if(!getword()) return;
  309. /* Флаги передаются в двух байтах по схеме:
  310.       | RESERVED u_blk | RESERVED  async_msgs |
  311.     H/| 765432    1 0  | 7654321       0      |/L
  312.     async_msgs - асинхронные сообщения (0 - запретить, 1 - разрешить)
  313.     u_blk - напряжение удержания (00 - нет, 01 - 9, 10 - 12, 11 - 24)
  314. */
  315.     async_msgs = d_L & 1;
  316.     block = (8 >> (d_H & 3)) & 7;
  317. }
  318.  
  319. void  on_interrupt() __interrupt 0{ // обработка прерываний
  320.     if(RCIF == 1){  // поступило прерывание от USART
  321.         if(get9bit() != OK) return;
  322.         switch(cmd){
  323.             case INIT:          init(); break;
  324.             case SET09V:        change_voltage(NINE); break;
  325.             case SET12V:        change_voltage(TWELVE); break;
  326.             case SET24V:        change_voltage(TWENTYFOUR); break;
  327.             case STEP_LEFT:     step(LEFT); break;
  328.             case STEP_RIGHT:    step(RIGHT); break;
  329.             case DPM1L:         dpm(0); break;
  330.             case DPM1R:         dpm(2); break;
  331.             case DPM2L:         dpm(4); break;
  332.             case DPM2R:         dpm(6); break;
  333.             case DPM1L2L:       dpm(8); break;
  334.             case DPM1L2R:       dpm(10); break;
  335.             case DPM1R2L:       dpm(12); break;
  336.             case DPM1R2R:       dpm(14); break;
  337.             case DPM1_STOP:     dpm(16); break;
  338.             case DPM2_STOP:     dpm(18); break;
  339.             case ISSTEP:        isstep = 1; break;
  340.             case ISNTSTEP:      isstep = 0; break;
  341.             case STEP_L_NUM:    rot_step(LEFT); break;
  342.             case STEP_R_NUM:    rot_step(RIGHT); break;
  343.             case STEP_STOP:     steps = 0; dpm(20); break;
  344.             case TOTAL_STEPS:   tot_steps(); break;
  345.             case SET_TIMER:     if(getword()){
  346.                                     TMR_H = d_H; TMR_L = d_L;
  347.                                     timer1set(ON);}
  348.                                 else send9bit(ERR_CMD);
  349.                                 break;
  350.             case STOP_TIMER:    timer1set(OFF); break;
  351.             case TMR_SETTINGS:  sendword(TMR_H, TMR_L); break;
  352. //          case TEST:          test_flag = !test_flag; break;
  353.             case TERM_METHOD:   get_term_method(); break;
  354.             case RESERVED_FLAGS: get_flags(); break;
  355.             case TERMINALS:     send9bit(PORTB);
  356.             //default: send9bit(ERR_CMD); break;
  357.         }
  358.     }
  359.     if(TMR1IF == 1) // поступило прерывание от таймера
  360.         timer1int(); // обработать прерывание
  361. }
  362.  
  363. void main(){ // основной цикл
  364.     init();
  365.     while(1){};//CLRWDT};
  366. }
  367.  
  368.  
Advertisement
Add Comment
Please, Sign In to add comment