The purpose of this project is to take input from the rotary encoder and display its value on three 7-segment displays. The rotary encoder outputs its value in gray code, so it must be converted to a binary value. To display this binary value, it must be converted to a binary-coded-decimal (BCD). Transistors must be used to cycle through the 7-segment displays in order to give the appearance of every display being on at once.
|4-Bit Gray-Code Rotary Encoder||3× 7-Segment Display|
|CD4511BE BCD to 7-Segment Display IC||4× 1MΩ Resistor|
|3× 3904 NPN Transistor||3× 1kΩ Resistor|
This challenge started by wiring the rotary encoder to an existing 7-segment BCD display circuit. The initial circuit consisted of a 4511 IC connected to three 7-segment displays. The displays achieved persistence of vision (POV) by toggling the ground connection through the use of NPN transistors. The wiring of the rotary encoder is nearly the same as that in Challenge 1 Rotary Switch Monitor.
The real difference is in the output from the rotary encoder. Instead of returning a binary number according to the position of the rotor, the encoder used here returns a "Gray code" value. Gray code is very different from binary. Instead of being a "weighted" number system, wherein a change in a specific digit always has the same affect on a number, Gray code is unweighted. This makes it a code instead of a number system. The key feature of Gray code is that between each number only one bit changes value. When using binary, multiple bits often change from a 1 to a 0 while incrementing or decrementing number value. This reduces ambiguity between number states and, in extreme cases, can reduce wear on memory. At right is the bottom view of Gray code rotary encoder, with white squares being zeros and black squares representing ones.
The code does the brunt of the work in this challenge. The code consists of three main parts. First, the program takes input from the rotary encoder attached to
PORTD and converts the Gray code to a binary value. Next, the code converts this to a BCD value on
r18. Finally the program displays these values on the 7-segment displays using POV. The code then loops to constantly poll the input states of the rotary encoder.
In the first step of the input portion, the
collect function stores the input state of
PORTD to a register. It then shifts this register right, as the zero pin of
PORTD does not have input, and the first input is instead on pin one. To convert the Gray code to binary, the
convert function adds the binary value of the gray code input to the value of the x register and stores this in the z register. Next it queries the value stored at this position in memory. Here it returns a binary value equivalent to the Gray code. This is because the register stores the binary conversion of the Gray code at the index of the direct binary value of the gray code. For example, while Gray code
0b0011 is a two, the direct binary value is three.
Next, the program converts the binary value to a BCD. Beginning at the
loop label, the program shifts the input value left through the output registers, carrying the dropped value into each consecutive register. Here the
iterate register decrements, as the algorithm must know whether or not the input number is fully converted or not. Next the program checks if the low bit of the first register is greater than or equal to three. The value of this register increases by three if this condition is true. The
tens label repeats this step for the high bit of the first register. Instead, however, it checks if the register has a value greater than 80 (0x50) and adds 48 (0x30) if this condition is true. Again, this step repeats under the
hundreds label, checking the low bit of the second register and adding three accordingly. Here it jumps back to the
loop label. The input value is fully converted to BCD when the
iterate register reaches zero.
In the final part, the
pov function takes the registers storing the BCD value and outputs the according number to the 4511 BCD to 7-segment display chip. The hundreds register displays first, with output on
PORTC. Next, the base pin of the according transistor activates by setting
PORTB. After displaying the hundreds digit, the tens digit is displayed by swapping the nibbles of the first register (
r17), and repeating the steps for the hundreds register. The transistor select register shifts by one to enable the tens display and disable the hundreds display. Next,
r17 swaps nibbles again and the above steps repeat, but for the ones digit. In the final step, the program jumps to the beginning of the program and the process repeats.
|Fritzing diagram||Circuit overview|
|Proper operation showing output 14||Bottom of rotary encoder|
|Link to YouTube Video: https://youtu.be/K7AFz38Lux8|
; GrayCodeChallenge.asm ; ; Created: 2018-01-15 8:57:57 AM ; Author : Ethan McAuliffe iterate = r24 temp = r25 three = r23 threeTens = r22 0x0000 rjmp reset ;segment table format: ;gfab_cde. 0x0010 grayStart: 0,1,3,2,7,6,4,5,15,14,12,13,8,9,11,10 grayEnd: reset: ldi r16, low(RAMEND) ;ALL assembly code should start by out spl,r16 ; setting the Stack Pointer to ldi r16, high(RAMEND) ; the end of SRAM to support out sph,r16 ; function calls, etc. ldi xl,low(grayStart<<1) ;position X and Y pointers to the ldi xh,high(grayStart<<1) ;start and end addresses of ldi yl,low(grayEnd<<1) ; our data table, respectively ldi yh,high(grayEnd<<1) movw z,x ;start Z pointer off at the start address of the table. ldi r16,0x1E out DDRD,r16 ldi r16,0x07 out DDRB,r16 ;pins to control transistors ldi r16,0x0F out DDRC,r16 ;pins to control 7-segment driver collect: clr r16 clr r17 clr r18 in r16,PIND ;store input from rotary encoder lsr r16 ;shift right to get gray code movw z,r16 ;move to element the gray code is in binary add zl,xl lpm r18,z ;store fetched binary value convert: mov r16,r18 ldi iterate, 8 ldi three, 0x03 ldi threeTens, 0x30 clr r17 clr r18 loop: rol r16 rol r17 rol r18 ;shift value and BCD registers with carry dec iterate breq pov ;jump to POV if there are no bits left to convert mov temp, r17 andi temp, 0x0F cpi temp, 0x05 brlo tens ;skip to tens if value is less than 5 add r17,three ;otherwise add three tens: cpi temp, 0x50 brlo hundreds add r17,threeTens hundreds: andi temp, 0x0F cpi temp, 0x50 brlo loop add r18, three rjmp loop pov: out PORTC,r18 ;output hundreds value ldi r16,0x04 out PORTB,r16 ;enable hundreds 7-seg disp rcall delay lsr r16 swap r17 out PORTC,r17 ;output tens value out PORTB,r16 ;enable tens 7-seg disp rcall delay lsr r16 swap r17 out PORTC,r17 ;output ones value out PORTB,r16 ;enable ones 7-seg disp rcall delay rjmp collect delay: ; Generated by delay loop calculator ; at http://www.bretmulvey.com/avrdelay.html ; ; Delay 16 000 cycles ; 1ms at 16 MHz ldi r19, 21 ldi r20, 199 L1: dec r20 brne L1 dec r19 brne L1 ret
To conclude, I am satisfied with the final result of this project. Unfortunately, I was not able to have operational code by the end of the challenge period. After working on my program throughout the week, however, I was able to get a working solution. My initial code was organized properly, but not operational. This challenge has adequately tested my knowledge of assembly code. It has also helped me develop my understanding of Gray code and a broader understanding on conversion algorithms/techniques.
D'Arcy, Chris. "TEI4M Challenges." ACES, RSGC, 15 Jan. 2018, darcy.rsgc.on.ca/ACES/TEI4M/1718/Challenges.html#2.
Grayhill. "Series 25L." Grayhill.com, Digi-Key, www.grayhill.com/assets/1/7/Mech_Encoder_25L.pdf.