Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <main.h>
- /*
- STILL WORK IN PROGRESS!!!
- This code will be later mixed with the stepper driver code, as it's supposed to be a driver for a
- motorized equatorial mount. Every function will be kept, particularly those related to the 7-seg
- display driver.
- ### Description:
- This code allows you to drive up to 8 digits 7-segments display with two 74HC595 (shift register
- with tristate output and latch). Tested only with 4 digits, but, asides the BCD converter, it
- should work flawlessly with minor modifications. On default, the first register controls each
- segment and the second register controls the digit to show, but that can be also easily modified.
- Tested on a PIC16F628A, running at 4MHz (internal RC oscillator). Compiled with CCS.
- Author: Franco Sauvisky
- ### Operation and tips:
- The fully encoded number has to be stored in a 4-bytes array, and it will switch between each
- single digit every time you call the function update_disp(). If time is required between switching
- digits - for example, to process some data - it's recommended to shutdown the display temporarily
- so it won't outshine a single digit (keep in mind that, after the function is called, it will keep
- that digit "on"). That might be done by setting the OE (output enable) pin or by calling the
- function clear_disp(), that sends two null bytes to the 74HC595 turning every output low. The same
- function might be also used for synchronizing the register when not using the MR (Master Reset)
- pin, though usually flushing any data will do the same.
- The default mapping of segments for each bit is: byte = [A] [B] [C] [D] [E] [F] [G] [DT].
- Some functions uses the fast_io directive. It only tells the compiler to don't change the tris
- value every time, so it can operate faster. The biggest problem is that you can only set up it for
- whole ports, so, when using different pins from the default, you might need to change it or add
- another one.
- It should cause no difference in other parts of the code, since it will return to standard_io on
- the end of the function, though you should not use the same pins for input, or let the tris go
- high, as that won't let the microcontroller modify those pins. If wanted, it can be removed without
- any hiss, although that will make the process slower.
- There are two main modes of operation. You can refresh the full display (by calling update_disp()
- multiple times) and then do the data processing (previously turning off the display so every digit
- will be evenly bright) or you might assign an interrupt to a timer, in a manner that it will
- refresh the display automatically. That allows you to run any code freely, only using load_num()
- for modifying the display, and it's guaranteed that the brightness will keep constant and equal
- between digits. The cons of that method is the longer execution time, as it will be constantly
- interrupted for some time.
- ### Functions:
- - sreg_init(): Resets the 74HC595, enables output and set every pin low (but MR).
- - sreg_send_long(int8 low, int8 high): Sends two int8 and clocks latch.
- - sreg_clear(): Sends 0x0000, setting every 74HC595 output low. Needed when not using OE and/or
- MR pins.
- - load_num(int16 numb, int dots, int *coded): Converts a int16 into a 7-segments A-G coded
- 4 elements array, plus decimal points.
- - update_disp(int *encoded): Switches to the next character in enc7seg array. Needs to be
- called once for each digit. The digit bits are inverted, that is, the "on" digit will be a low
- output, though is simple to modify that behavior. The digit counter is internal (static variable).
- - update_disp_but(int *encoded, int pcount): Same function than previously, though it allows you
- to choose manually which digit to display. It might be used for scanning buttons. On default, it
- will output the digit selector nibble twice, using some pins for button scanning and others for
- selecting digit, but I don't see why you wouldn't be able to use the same (allowing you to drive
- eight digits plus scanning up to eight buttons on the same pins).
- - copy_arr(int *dest, int *src): Copies 4 bytes of src to dest. Useful when using presets for
- displaying texts and symbols, though memcpy() does the same (and can work with constant arrays,
- which this one can't). The biggest benefit is the low memory used.
- - wait_for_button_press(int *buttons): Waits for any bit setting modification (i.e. positive edge)
- on *buttons and returns which button/bit has been pressed/set.
- - write_play() (not used): Writes "play" on the display. Sample code for testing non-numeric
- data and manually setting each segment.
- ### Global Variables:
- - seven_seg_map[] (constant): Lookup table for BCD -> 7-segments conversion.
- - one_bit_shift[] (constant): This array is used as a lookup table for situations where is needed
- to test a single bit quickly, as the ALU shifter usually takes some time (because it only can shift
- one position per time, needing multiple shifts for testing bits farthest from LSB).
- */
- #define sh_cp pin_b7 // Shift Register Clock (shift on low -> high)
- #define st_cp pin_b6 // Storage Register (Latch) Clock (low -> high)
- #define ds_in pin_b5 // Serial Input
- #define mr_in pin_b4 // Master Reset (reseted low, not critical)
- #define oe_in pin_b2 // Output Enable (enabled low, not critical)
- #define button pin_b0 // Button Input
- void sreg_init();
- void sreg_send_long(int8 low, int8 high);
- void sreg_clear();
- void load_num(int16 numb, int dots, int *coded);
- void update_disp(int *encoded);
- void update_disp_button(int *encoded, int pcount);
- void copy_arr(int *dest, int32 src);
- int wait_for_button_press(int *buttons);
- int16 number_input(int16 stnumber, int *buttons_status, int *codpointer);
- void write_play();
- void motor_ustep_pwm(int steps, int count);
- const int seven_seg_map[] = { 0xFC, 0x60 0xDA 0xF2, 0x66, 0xB6, 0xBE, 0xE0, 0xFE, 0xF6, 0x00 };
- const int one_bit_shift[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };
- const int16 power_ten[] = { 1, 10, 100, 1000, 10000 }; // Constant for selecting which digit to
- // increase or decrease.
- // ########################## CODE FOR TESTING PURPOSE ONLY (DEMO) ##########################
- // [OLD] This demo was compiled on CCS (PCM) and ran on a PIC16F628A. It is supposed to use a 4
- // digits display, allowing you to modify a number by selecting a digit with two buttons and
- // increasing or decreasing it with another two buttons. Though the clocking frequency is low and
- // much of the time is keep updating the display, it feels very intuitive and responsive.[/OLD]
- // # MODIFIED: Now it's supposed to be a driver for an motorized equatorial mount, configurable.
- const int preset_run[] = { 0x00, 0x2A, 0x38, 0x0A }; // Presets for the display
- const int preset_inte[] = { 0x9E, 0x1E, 0x2A, 0x20 };
- const int preset_step[] = { 0xCE, 0x9E, 0x1E, 0xB6 };
- const int preset_erro[] = { 0xFC, 0x0A, 0x0A, 0x9E };
- const int preset_rset[] = { 0x1E, 0x9E, 0xB6, 0x0A };
- int codednum[4];
- int buttons=0;
- #priority int_timer1, int_timer2, int_ext
- #int_timer2
- void tmr2int()
- {
- static int tcount;
- update_disp_button(codednum,tcount);
- if(!input(button))
- {
- buttons |= one_bit_shift[tcount];
- }
- else
- {
- buttons &= ~one_bit_shift[tcount];
- }
- tcount = (tcount+1) % 4;
- }
- #int_timer1
- void tmr1int()
- {
- static int pwmcount=0;
- pwmcount=(pwmcount+1) % 64;
- motor_ustep_pwm(8,pwmcount);
- }
- // Button bit map:
- // 1 and 2: Left/Decrease and Right/Increase
- // 3: Set/Go/Play
- // 4: Back
- void main()
- {
- sreg_init();
- port_b_pullups(true); // Pull-up for button scanning.
- setup_timer_2(t2_div_by_16,150,1); // On a 4MHz clock, it changes digit every 24ms.
- enable_interrupts(global);
- enable_interrupts(int_timer2);
- int menuitem=0;
- int tempb;
- int ustep=read_eeprom(0x00); // Load last settings
- int16 intval=~read_eeprom(0x01);
- intval<<=8;
- intval|=~read_eeprom(0x02);
- int pwmcount;
- while(true)
- {
- switch(menuitem)
- {
- case 0:
- memcpy(codednum,preset_run,4);
- tempb=wait_for_button_press(&buttons);
- if(tempb==4)
- {
- delay_ms(30);
- disable_interrupts(int_timer2);
- sreg_clear();
- output_a(0x00);
- setup_timer_2(t2_div_by_1,255,1);
- setup_ccp1(ccp_pwm);
- setup_timer_1(t1_internal | t1_div_by_4);
- enable_interrupts(int_timer1);
- if(input(pin_b0)) while(!input(pin_b0));
- while(input(pin_b0));
- disable_interrupts(int_timer1);
- setup_ccp1(ccp_off);
- setup_timer_2(t2_div_by_16,150,1);
- enable_interrupts(int_timer2);
- }
- break;
- case 1:
- memcpy(codednum,preset_inte,4);
- tempb=wait_for_button_press(&buttons);
- if(tempb==4) intval=number_input(intval, &buttons, codednum);
- write_eeprom(0x01,~intval>>8);
- write_eeprom(0x02,~intval);
- break;
- case 2:
- memcpy(codednum,preset_step,4);
- tempb=wait_for_button_press(&buttons);
- break;
- case 3:
- memcpy(codednum,preset_rset,4);
- tempb=wait_for_button_press(&buttons);
- if(tempb==4)
- {
- write_eeprom(0x00,0xFF);
- write_eeprom(0x01,0xFF);
- write_eeprom(0x02,0xFF);
- reset_cpu();
- }
- break;
- }
- if(tempb==2)
- {
- menuitem=(menuitem+1) % 4;
- }
- else if(tempb==1)
- {
- menuitem=(menuitem+3) % 4;
- }
- }
- }
- // ################################## END OF TESTING CODE ##################################
- // -----------------------------------------------------------------------------------------
- // ############################# DISPLAY CONTROLLER FUNCTIONS #############################
- void sreg_init()
- {
- output_low(sh_cp);
- output_low(ds_in);
- output_low(mr_in);
- output_high(mr_in);
- output_high(st_cp);
- output_low(st_cp);
- output_low(oe_in);
- }
- void sreg_send_long(int8 high, int8 low)
- {
- #use fast_io(B) // Change, add or remove if using another pins.
- output_low(sh_cp);
- for(int i=0; i<8; i++)
- {
- output_bit(ds_in,high&0x80);
- output_high(sh_cp);
- output_low(sh_cp);
- high<<=1;
- }
- for(i=0; i<8; i++)
- {
- output_bit(ds_in,low&0x80);
- output_high(sh_cp);
- output_low(sh_cp);
- low<<=1;
- }
- output_low(st_cp);
- output_high(st_cp);
- output_low(st_cp);
- #use standard_io(B) // This also.
- }
- void sreg_clear()
- {
- output_low(sh_cp);
- for(int i=0; i<16; i++)
- {
- output_high(sh_cp);
- output_low(sh_cp);
- }
- output_low(st_cp);
- output_high(st_cp);
- output_low(st_cp);
- }
- void load_num(int16 numb, int dots, int *coded)
- {
- int bcd_digit;
- for(int i=0; i<4; i++)
- {
- bcd_digit = (numb % 10);
- numb /= 10;
- coded[i]=seven_seg_map[bcd_digit]|(bit_test(dots,i));
- }
- }
- void update_disp(int *encoded)
- {
- static int count;
- sreg_send_long(~one_bit_shift[count],encoded[count]);
- count=(count+1)&4;
- }
- void update_disp_button(int *encoded, int pcount)
- {
- int digsel=~(one_bit_shift[pcount]+(one_bit_shift[pcount]<<4));
- sreg_send_long(digsel,encoded[pcount]);
- }
- void copy_arr(int *dest, int *src)
- {
- dest[0]=src[0];
- dest[1]=src[1];
- dest[2]=src[2];
- dest[3]=src[3];
- }
- int wait_for_button_press(int *buttons_status)
- {
- int temp;
- int start;
- do
- {
- start=*buttons_status;
- while(*buttons_status==start);
- temp = (*buttons_status^start)&~start;
- } while(temp==0);
- return temp;
- }
- int16 number_input(int16 stnumber, int *buttons_status, int *codpointer)
- {
- int pos=3;
- int16 tempn=0;
- int1 returnflag=0;
- load_num(stnumber,one_bit_shift[pos],codpointer);
- while(!returnflag)
- {
- switch(wait_for_button_press(buttons_status))
- {
- case 1:
- tempn=stnumber-power_ten[pos];
- if(tempn<10000){ stnumber = tempn; };
- break;
- case 2:
- tempn=stnumber+power_ten[pos];
- if(tempn<10000){ stnumber = tempn; };
- break;
- case 4:
- pos=(pos+3) % 4;
- break;
- case 8:
- returnflag=1;
- break;
- default:
- break;
- }
- load_num(stnumber,one_bit_shift[pos],codpointer);
- }
- return stnumber;
- }
- void write_play()
- {
- int play[] = { 0x3B, 0x77, 0x0E, 0x67 };
- output_low(oe_in);
- while(true)
- {
- update_disp(&play);
- }
- }
- // ########################### END OF DISPLAY FUNCTIONS ###########################
- // Count: 0~64 (8 "macro" steps * 8 microsteps)
- // Steps: 1 (full), 2 (half), 4 (1/4 micro), 8 (1/8 micro). Needs more steps?
- // Even when not using 1/8 microstepping, the software will "ignore" smaller increases till it
- // reaches next step. At least that is my plan.
- // #### This piece of code will be slight more ad hoc, as it is designed to work on an specific
- // circuitry. Though the code might be useful for something...
- const int hdrive_map[] = { 1, 4, 4, 2, 2, 8, 8, 1 }; // Odd: decrease, Even: increase PWM
- const int htrisa_map[] = { 4, 1, 2, 4, 8, 2, 1, 8 };
- const int16 pwm_ustep[] = { 179, 331, 463, 580, 686, 781, 868, 949 }; // PWM values calculated for
- // timer2 without prescale (divide by 1) and PR2 = 150.
- // 341, 482, 591, 682, 762, 835, 902, 964 -> sqrt
- // 179, 331, 463, 580, 686, 781, 868, 949 -> log
- // 143, 271, 387, 497, 602, 705, 808, 913 -> log(tan)
- // 90, 180, 274, 372, 477, 591, 716, 858 -> tan
- // 114, 227, 341, 455, 568, 682, 796, 909 -> lin
- void motor_ustep_pwm(int steps, int count)
- {
- int macrostep = count / 8;
- int ustep = count % 8;
- if(steps>=4)
- {
- output_a(hdrive_map[macrostep]);
- set_tris_a(htrisa_map[macrostep]);
- ustep = (macrostep & 0x01)? 7-ustep : ustep;
- ustep = steps==4 ? ustep&0x0E : ustep;
- set_pwm1_duty(pwm_ustep[ustep]);
- }
- }
- /*void motor_ustep_pwm(int steps, int count) // Old version, didn't mananged to get it right.
- {
- int pintmp;
- int1 flag;
- int hstep=count/8; // Which "macrostep" (halfstep) it should be at.
- int next=hdrive_map[hstep]; // Next pin map to set
- int curr = hstep;
- curr = (curr+7) % 0x08; // Desceases 1 with rollover.
- curr=hdrive_map[hstep]; // Old pin map.
- if(next>curr) // Detects if it needs to rise or turn down pin.
- {
- pintmp=next-curr;
- flag=1;
- }
- else
- {
- pintmp=curr-next;
- flag=0;
- }
- set_tris_a(pintmp); // Sets the pin to increase/decrease to high impedance, allowing the PWM
- // signal to pass though.
- output_a(next); // Sets the pin map. As the current changing pin it's floating, doesn't
- // matters if it is set up or down.
- int ustep=count % 0x08; // Which microstep it should be at. 3 LSBs of count.
- ustep = flag ? ustep : 7-ustep; // If it needs to decrease the PWM value of the pin (turning it
- // down), it "mirrors" the ustep.
- set_pwm1_duty(pwm_usteps[ustep]); // Sets the duty to the PWM CCP. pwm_ustep rises (0%-100%).
- }*/
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement