/***************************************************** This program was produced by the CodeWizardAVR V1.25.3 Professional Chip type : ATtiny2313 Clock frequency : 20,000000 MHz = 50 нС = 0.05 мкС Memory model : Tiny External SRAM size : 0 Data Stack size : 32 Автор: petropavlovsk5@mail.ru Денисюк Михаил 26 лет *****************************************************/ // дисплей WH1602 HD44780 // 4...7 <--> PORTD0...3 // E <--> PORTD.4 // RW <--> PORTD.5 // RS <--> PORTD.6 // оптодатчик нуль-метка PORTB.3 // Сигналы A и B на PORTB.0 и 1 // все фьюзы =1 #include #include #define clear_bit( reg, bitNumb ) ((reg) &= ~(1 << (bitNumb))) #define set_bit( reg, bitNumb ) ((reg) |= (1 << (bitNumb))) #pragma optsize- //optimize for speed #pragma regalloc- //I allocate the registers myself register unsigned char MaskNewTempX @2; register unsigned char MaskLastTempX @3; register unsigned char NewTempX @4; register unsigned char LastTempX @5; register unsigned char NewZeroX @6; register unsigned char LastZeroX @7; register unsigned char Sost_PINB @8; // состояние входных сигналов от датчика register unsigned char nX @9; // направление вращения register signed int RotateX @10; // R10:R11 угловое положение датчика X register signed int temp @12; // R12:R13 временный буфер volatile signed int riskiX @0x70; // кол-во рисок на датчике volatile unsigned char StartX @0x72; // если еще не проходила нуль-метка volatile unsigned char ErrorX @0x73; // пропустил риски volatile char OborotX @0x74; // количество оборотов по X volatile char OborotLastX @0x75; // предыдущее количество оборотов volatile unsigned char Thou @0x60; // bcd числа для вывода на HD44780 непрерывно volatile unsigned char Hund @0x61; // volatile unsigned char Tens @0x62; // volatile unsigned char Ones @0x63; // volatile unsigned char TenThou @0x64; volatile unsigned char My4 @0x65; // старший разряд углового положения датчика volatile unsigned char My5 @0x66; // младший разряд углового положения датчика #pragma regalloc+ void delay_us(unsigned int); void delay_ms(unsigned int); void COMMAND (unsigned char); void data_write(unsigned char); void BIN2DEC2(void); void InitLCD(); void outcomLCD(char); char busyLCD(); void outsymLCD(char); char readLCD(); #pragma savereg- // выкл автосохранения регистров - сами сохраняем // Pin change 0-7 interrupt service routine interrupt [PCINT] void pin_change_isr0(void) { // R0,R1,R15,R22...R27,R30,R31,SREG сохраняются при работе в СИ по умолчанию #pragma savereg+ #asm push r0 ; push r1 ; push r15 push r22 push r23 push r24 push r25 push r26 push r27 push r30 push r31 in r22,SREG push r22 #endasm // EIFR=0x20; флаг того что произошло прерывание на линии PCIE Sost_PINB = PINB; // прочитали состояние портов от датчика NewTempX = (Sost_PINB & 0b00000111); // побитовое И // 2-битный Код ГРЕЯ. вращение вперед 00->01->11->10. вращение назад 00<-01<-11<-10 if (NewTempX!=LastTempX) { MaskNewTempX= NewTempX&0b00000011; MaskLastTempX= LastTempX&0b00000011; if (MaskNewTempX!=MaskLastTempX) { switch (MaskLastTempX) { case 0: {switch (MaskNewTempX) { case 1: RotateX++; nX=1; break; // вперед case 2: RotateX--; nX=0; break; // назад default: ErrorX=1; break; // case 3 не видит риски по A или B } break; } case 1: {switch (MaskNewTempX) { case 3: RotateX++; nX=1; break; //вперед case 0: RotateX--; nX=0; break; //назад default: ErrorX=1; break; // case 2 не видит риски по A или B } break; } case 2: {switch (MaskNewTempX) { case 0: RotateX++; nX=1; break; // вперед case 3: RotateX--; nX=0; break; // назад default: ErrorX=1; break; //case 1 не видит риски по A или B } break; } case 3: { switch (MaskNewTempX) { case 2: RotateX++; nX=1; break; // вперед case 1: RotateX--; nX=0; break; // назад default: ErrorX=1; break; // case 0 не видит риски по A или B } break; } } } } // Для нуль метки NewZeroX= (NewTempX>>2)&0b00000001; LastZeroX= (LastTempX>>2)&0b0000001; if (NewZeroX!= LastZeroX) { switch (NewZeroX) { case 1: { if (StartX==0) {StartX=1;} else if (StartX==1) {StartX=2; riskiX = RotateX;} RotateX = 0; break; } case 0: { OborotLastX=OborotX; if (nX==1) {OborotX++; break; } // если с нуль-метки датчик пошел не вперед а назад if (nX==0) {OborotX--; break; } // если с нульметки датчик пошел не назад а вперед } } if ((OborotX==0xFF)&&(nX==0)) OborotX = 9; if ((OborotX==10)&&(nX==1)) OborotX = 0; } LastTempX=NewTempX; #asm pop r22 out SREG, r22 pop r31 ; pop r30 ; pop r27 pop r26 ; pop r25 ; pop r24 ; pop r23 ; pop r22 ; pop r15 pop r1 pop r0 #endasm } void data_write (unsigned char perem) //вывод данных без опроса флага занятости { delay_us(40); //delay_ms(2); DDRD=0xFF; // на вывод PORTD=(perem>>4)|0x40; // RS=1, E=0, RW=0 #asm("nop"); //>40нС PORTD=(perem>>4)|0x50; // RS=1, E=1 #asm("nop"); // >230 nS задержка #asm("nop"); #asm("nop"); #asm("nop"); #asm("nop"); clear_bit( PORTD,4); //E=0; #asm("nop"); // 10нС PORTD = (perem&0b00001111)|0x40; // RS=1, E=0, RW=0 #asm("nop"); //>40нС PORTD = (perem&0b00001111)|0x50; // RS=1, E=1 #asm("nop"); // 230 nS задержка #asm("nop"); #asm("nop"); #asm("nop"); #asm("nop"); clear_bit( PORTD,4); //E=0; #asm("nop"); } void COMMAND(unsigned char perem) //вывод команды на LCD: RS=0, RW=0 без опроса флага занятости { delay_us(40); //delay_ms(2); DDRD=0xFF; // на вывод PORTD=(perem>>4); // E=0 #asm("nop"); PORTD=(perem>>4)|0x10; // E=1; #asm("nop"); // 230 nS задержка #asm("nop"); #asm("nop"); #asm("nop"); #asm("nop"); clear_bit( PORTD,4); //E=0; #asm("nop"); PORTD = (perem&0b00001111); // E=0 #asm("nop"); PORTD = (perem&0b00001111)|0x10; // E=1; #asm("nop"); // 230 nS задержка #asm("nop"); #asm("nop"); #asm("nop"); #asm("nop"); clear_bit( PORTD,4); //E=0; #asm("nop"); } void main(void) { // Crystal Oscillator division factor: 1 CLKPR=0x00; PORTA=0x00; DDRA=0x00; PORTB=0xFF; // подтяг резисторы DDRB=0x00; // на вход PORTD=0x00; DDRD=0xFF; // на выход // Timer/Counter 0 initialization // Clock source: System Clock // Clock value: Timer 0 Stopped // Mode: Normal top=FFh // OC0A output: Disconnected // OC0B output: Disconnected TCCR0A=0x00; TCCR0B=0x00; TCNT0=0x00; OCR0A=0x00; OCR0B=0x00; // External Interrupt(s) initialization // INT0: Off // INT1: Off // Interrupt on any change on pins PCINT0-7: On MCUCR=0x00; // Timer/Counter 1 initialization // Clock source: System Clock // Clock value: 19,531 kHz // Mode: CTC top=OCR1A // OC1A output: Discon. // OC1B output: Discon. // Noise Canceler: Off // Input Capture on Falling Edge // Timer 1 Overflow Interrupt: Off // Input Capture Interrupt: Off // Compare A Match Interrupt: On // Compare B Match Interrupt: Off TCCR1A=0x00; // CTC режим, max=OCR1A TCCR1B=0x0D; // 1101 предделитель на 1024 TCNT1H=0x00; // начальные значения TCNT1L=0x00; ICR1H=0x00; // захват не используется ICR1L=0x00; OCR1AH=0x98; // сравнение с этим числом OCR1AL=0x96; OCR1BH=0x00; OCR1BL=0x00; // TIFR,6 OCF1A очищается записью в этот бит // частота 20000000/1024=19531; 19531/39062=0.5 т.е. 2 секунды // Timer(s)/Counter(s) Interrupt(s) initialization TIMSK=0x00; // Universal Serial Interface initialization // Mode: Disabled // Clock source: Register & Counter=no clk. // USI Counter Overflow Interrupt: Off USICR=0x00; // Analog Comparator: Off // Analog Comparator Input Capture by Timer/Counter 1: Off ACSR=0x80; InitLCD(); StartX=0; // еще не было ноль метки RotateX=0; ErrorX=0; // ошибки OborotX=0; GIMSK=0x20; // включить прерывания при изменении входных сигналов PCIE PORTB PCMSK=0b00000111; // только PB0..PB2 вызовут прерывание то есть 1 датчик #asm("sei"); // set_bit( SREG, 7); I global interrupt enable LastTempX = (PINB & 0b00000111); // побитовое И // LastTempZ = (PORTB & 0b00111000) >>3; // побитовое И while (1) { // выбор ячейки видеопамяти DDRAM 0b1AAAAAAA, A - адрес (00..0F)1-я строка, (40..4F)2-я строка COMMAND(0b10000000); // в нулевую позицию первой строки outcomLCD COMMAND outsymLCD('X'); outsymLCD('='); // outsymLCD data_write temp=RotateX; temp=(temp>>2); // temp=temp/4; показания больше номинальных в четыре раза My4=(temp>>8); // старший разряд My5=(temp); // младший разряд if (temp<0) // если число отрицательное { // преобразуем его в положительное (инвертировать и прибавить 1) #asm push r19 ; push r20 ; push r22 ; in r22,SREG push r22 LDS R19, _My4 ; 73 старший разряд LDS R20, _My5 ; 74 младший разряд COM R19 COM R20 INC R20 STS _My4, R19; запись из регистра в память STS _My5, R20; запись из регистра в память pop r22 out SREG, r22 pop r22 ; pop r20 ; pop r19 #endasm BIN2DEC2(); outsymLCD(0x2D); // minus outsymLCD(TenThou);// outsymLCD outsymLCD(Thou); data_write(Hund); data_write(Tens); data_write(Ones); } else if (temp>0) { BIN2DEC2(); data_write(0x2B); // plus data_write(TenThou); data_write(Thou); data_write(Hund); data_write(Tens); data_write(Ones); }; // вывод количества рисок датчика if (StartX==2) { temp=riskiX; temp=(temp>>2); // temp=temp/4; показания больше номинальных в четыре раза My4=(temp>>8); // старший разряд My5=(temp); // младший разряд if (temp<0) // если самый старший бит=1 то число отрицательное { // преобразуем его в положительное (инвертировать и прибавить 1) #asm push r19 ; push r20 ; push r22 ; in r22,SREG push r22 LDS R19, _My4; ; 73 старший разряд LDS R20, _My5; ; 74 младший разряд COM R19 COM R20 INC R20 STS _My4, R19; запись из регистра в память STS _My5, R20; запись из регистра в память pop r22 out SREG, r22 pop r22 ; pop r20 ; pop r19 #endasm } BIN2DEC2(); COMMAND(0b10001001); // в 9-ю позицию первой строки outcomLCD data_write('R'); // outsymLCD data_write(0x3D); // = data_write(TenThou); data_write(Thou); data_write(Hund); data_write(Tens); data_write(Ones); StartX=1; } // if (OborotX!=OborotLastX) { COMMAND(0b11000000); // в 0-ю позицию второй строки data_write(0x4F); // O data_write('b'); // b data_write(0x6F); // o data_write(0x72); // r data_write(0x6F); // o data_write(0x74); // t data_write(0x3D); // = data_write(OborotX+0x30); }; if ((TIFR&0b01000000)==0b01000000) // флаг OCF1A {ErrorX=0; TIFR=TIFR|0b01000000; } if (ErrorX==0) { outcomLCD(0b11001010); // в 10-ю позицию второй строки data_write(0x20); // outsymLCD data_write(0x20); // outsymLCD } else if (ErrorX==1) { outcomLCD(0b11001010); // в 10-ю позицию второй строки data_write('E'); // outsymLCD data_write('r'); // outsymLCD }; } // конец while } //////////////////////////////////////////////// // LCD procedures //////////////////////////////////////////////// void InitLCD() //инициализация LCD { delay_ms(40); //40 COMMAND(0b00110000) ; delay_ms(5); // COMMAND(0b00110000) ; 5 0x30 Запись только одного старшего п/байта "0011" COMMAND(0b00100000) ; delay_ms(5); // 5 0x20 Запись только одного старшего п/байта "0010" COMMAND(0b00100000) ; delay_ms(5); // 5 Запись только одного старшего п/байта "0010" COMMAND(0b00101000); // 0x28 Шина 4-разрядная, 2 строки, символы 5x8 COMMAND(0b00001100); // 0x0C Включить отображение символов на экране, курсор не отображать (бит1), не мерцает (бит0) COMMAND(0b00000110); // 0x06 Инкремент АС после вывода каждого символа, сдвигов нет COMMAND(0b00000001); delay_ms(2); // Очистка экрана, АС=0 COMMAND(0b00000010); delay_ms(2);// AC=0,адресация на DDRAM,сброшены сдвиги, начало строки адресуется в начале DDRAM } char busyLCD() { if (readLCD()&0x80) return 1; else return 0; } // команда проверка занятости LCD void PICtoLCD() //сконфигурировать вывод на LCD { DDRD=0xFF; //порт D на 1111111 } void LCDtoPIC() //сконфигурировать ввод с LCD { DDRD=0b11110000 ; //порт D на IIII0000 } char readLCD() //RS=0, RW=1 read busy flag { char data; LCDtoPIC(); clear_bit(PORTD,6); //RS = 0 set_bit(PORTD,5); //RW=1 чтение set_bit(PORTD,4); //E=1 #asm("nop"); // 140nS #asm("nop"); #asm("nop"); data=PIND<<4; clear_bit(PORTD,4); //Е=0 #asm("nop"); // 10nS set_bit(PORTD,4); //E=1 #asm("nop"); // 140nS #asm("nop"); #asm("nop"); data=data+(PIND&0x0f); clear_bit(PORTD,4); //Е=0 #asm("nop"); // 10nS PICtoLCD(); return data; } //вывод данных на LCD: RS=1, RW=0 void outsymLCD(char data)//вывод на LCD { while (busyLCD()); set_bit(PORTD,6); //RS=1 clear_bit(PORTD,5); //RW=0 PORTD=(data>>4)|0x50; // RS=1, E=1 0x50=0b01010000; #asm("nop"); #asm("nop"); #asm("nop"); clear_bit(PORTD,4); //Е=0 #asm("nop"); PORTD=(data&0x0F)|0x50; //E=1 #asm("nop"); #asm("nop"); #asm("nop"); clear_bit(PORTD,4); //Е=0 #asm("nop"); } //вывод команды на LCD: RS=0, RW=0 void outcomLCD(char data)//вывод на LCD { while (busyLCD()); clear_bit(PORTD,6); //RS=0 clear_bit(PORTD,5); //RW=0 PORTD=(data>>4)|0x10; // E=1 #asm("nop"); #asm("nop"); #asm("nop"); clear_bit(PORTD,4); //Е=0 #asm("nop"); PORTD=(data&0x0F)|0x10; //E=1 #asm("nop"); #asm("nop"); #asm("nop"); clear_bit(PORTD,4); //Е=0 #asm("nop"); } //Преобразователь HEX40-BCD13 переделано до HEX16-BCD5. #pragma warn- void BIN2DEC2(void) // HI, LO { #asm push r0 ; push r1 ; push r15 push r16 ; записываем регистры в стек push r17 ; push r18 ; push r19 ; push r20 ; push r21 ; push r22 ; push r23 push r24 push r25 push r26 push r27 push r28 push r29 push r30 push r31 in r22,SREG push r22 CLR R16; CLR R17; CLR R18; LDS R19, _My4; ; 73 старший разряд LDS R20, _My5; ; 74 младший разряд ; ld r20,y ;R20=LOCHAR можно еще через вызов параметров ; ldd r19,y+1 ;R19=HICHAR ; LDS R19, _My4SaveX; ; 73 старший разряд ; LDS R20, _My5SaveX; ; 74 младший разряд ; CLR R25 ; замена ; CLR R26 ; замена ; CLR R27 ; замена 1000 000 000, 100 000 000 CLR R28 ; 10 000 000, 1000 000 CLR R29 ; 100 000, 10 000 CLR R30 ; 1000, 100 CLR R31 ; 10, 1 CLR - clear register LDI R24,40 ; load immediate загрузка немедленно константы 5x8=40 qwerty: subi r31,-0x33 ;add 0x33 вычитание константы из рагистра,ZCNVH sbrs r31, 3 ;if carry to bit 3 skip if bit in register is set subi r31, 3 ;subtract 3 sbrs r31, 7 ;if carry to bit 7 subi r31, 0x30 ;subtract 0x30 subi r30,-0x33 ; add 0x33 sbrs r30, 3 ; if carry to bit 3 subi r30, 3 ; subtract 3 sbrs r30, 7 ; if carry to bit 7 subi r30, 0x30 ; subtract 0x30 subi r29,-0x33 ; замена sbrs r29, 3 ; замена subi r29, 3 ; замена sbrs r29, 7 ; замена subi r29, 0x30 ; замена ; subi r28,-0x33 ; замена ; sbrs r28, 3 ; замена ; subi r28, 3 ; замена ; sbrs r28, 7 ; замена ; subi r28, 0x30 ; замена ; subi r27,-0x33 ; замена ; sbrs r27, 3 ; замена ; subi r27, 3 ; замена ; sbrs r27, 7 ; замена ; subi r27, 0x30 ; замена ; subi r26,-0x33 ; замена ; sbrs r26, 3 ; замена ; subi r26, 3 ; замена ; sbrs r26, 7 ; замена ; subi r26, 0x30 ; замена ; subi r25,-0x33 ; замена ; sbrs r25, 3 ; замена ; subi r25, 3 ; замена ; sbrs r25, 7 ; замена ; subi r25, 0x30 ; замена lsl r31 ; логический cдвиг влево простой rol r30 ; сдвиг влево через флаг переноса rol r29 ; в каждом регистре 2 полубайта ; rol r28 ; ; rol r27 ; r31-младший, r25-старший ; rol r26 ; rol r25 sbrc R16, 7 ;skip if msbit of input =0*/ ;set lsb of output*/ ori R31, 1 ; логическое или регистра и константы lsl R20 rol R19 rol R18 rol R17 ;shift input*/ rol R16 dec R24 ; регистр-1 brne qwerty ;repeat for all bits*/ CLR R27; CLR R28; add R28, R30; записываем R30 в R28 add R27, R30; записываем R30 в R28 SWAP R28; меняем местами полубайты ANDI R28, 0x0F; оставляем младший полубайт ANDI R27, 0x0F; оставляем младший полубайт CLR R30; ADD R30, R31; записываем R31 в R30 SWAP R30; меняем местами полубайты ANDI R30, 0x0F; оставляем младший полубайт ANDI R31, 0x0F; оставляем младший полубайт ; для HD44780 преобразуем цифры subi R29,-0x30 ;add 0x30 subi R28,-0x30 ;add 0x30 subi R27,-0x30 ;add 0x30 subi R30,-0x30 ;add 0x30 subi R31,-0x30 ;add 0x30 STS _TenThou, R29; запись из регистра в память STS _Thou, R28; запись из регистра в память STS _Hund, R27; запись из регистра в память STS _Tens, R30; запись из регистра в память STS _Ones, R31; запись из регистра в память pop r22 out SREG, r22 pop r31 ; pop r30 ; pop r29 ; pop r28 ; pop r27 pop r26 ; записываем регистры в стек pop r25 ; pop r24 ; pop r23 ; pop r22 ; pop r21 ; pop r20 ; pop r19 pop r18 pop r17 pop r16 pop r15 pop r1 pop r0 #endasm } #pragma warn+ // enable warnings