SparkFun Forums 

Where electronics enthusiasts find answers.

Your source for all things Atmel.
#101784
I have some project in school and I need some help. So project is make an asm code (asemmbly code)for 4 digit x 7-segment(4 digit multiplexed 7-seg) some thing like driver...so I have to control digits by PORTC (bits 0,1,2,3) and control segment's leds by PORTB (B0,...,B7), by using timer0 overflow interrup and ATmega32..:!!interrupt time is about 4 ms. so how to show as example 0x1101 number on my segments?
I have done some code but I don't know how to continue::
here is my code

;----------------------------------------------
;7-Segment


;----------------------------------------------

.include "m32def.inc"

.equ Nbr_of_digits=4
.equ A=0x0111

.dseg
.org 0x60
t0_ovf_cnt: .byte 2 ;timer 0 overflow counter(16-bit)
B: .byte 2

.org 0x100
Result: .byte 20

.cseg
.org 0
jmp Reset

jmp EXT_INT0_SVC
jmp EXT_INT1_SVC
jmp EXT_INT2_SVC

jmp TIMER2_COMP_SVC
jmp TIMER2_OVF_SVC
jmp TIMER2_CAPT_SVC

jmp TIMER1_COMPA_SVC
jmp TIMER1_COMPB_SVC
jmp TIMER1_CVF_SVC

jmp TIMER0_COMP_SVC
jmp TIMER0_OVF_SVC

jmp ST_COMPLETE_SVC ;serial transfer complete
jmp RX_COMPLETE_SVC
jmp DR_EMPTY_SVC ;USART DATA Reg Empty
jmp TX_COMPLETE_SVC

jmp AD_READY_SVC
jmp EEPROM_READY_SVC

jmp ANA_COMA_SVC
jmp TWI_SVC ;2 Wire Serial Interface
jmp SPM_READY_SVC

RESET:
ldi r16, LOW(RAMEND)
out spl,r16
ldi r16,HIGH(RAMEND)
out sph,r16

ldi YL,LOW ( Result )
ldi YH,HIGH( Result )



call TIMER0_OVF_SVC_INIT
call ShowHex


sei ;Global Interrupt Enable


LOOP:
rjmp LOOP

TIMER0_OVF_SVC_INIT:


in r16,TCCR0
ori r16,(1<<CS00)
;ori r16,(1<<CS02)|(1<<CS00)
out TCCR0, r16

in r16,TIMSK
ori r16,(1<<TOIE0)
out TIMSK,r16

clr r16
sts t0_ovf_cnt,r16
sts t0_ovf_cnt+1,r16

ret

TIMER0_OVF_SVC:

push r24
in r24,SREG
push r24
push r25

lds r24,t0_ovf_cnt
lds r25,t0_ovf_cnt+1
adiw r25:r24,1
sts t0_ovf_cnt,r24
sts t0_ovf_cnt+1,r25


pop r25
pop r24
out SREG,r24
pop r24
sei
ldi r19,Nbr_of_digits
dec r19
breq TIMER0_OVF_SVC_INIT


reti

EXT_INT0_SVC:
EXT_INT1_SVC:
EXT_INT2_SVC:
TIMER2_COMP_SVC:
TIMER2_OVF_SVC:
TIMER2_CAPT_SVC:
TIMER1_COMPA_SVC:
TIMER1_COMPB_SVC:
TIMER1_CVF_SVC:
TIMER0_COMP_SVC:
;TIMER0_OVF_SVC:
ST_COMPLETE_SVC:
RX_COMPLETE_SVC:
DR_EMPTY_SVC:
TX_COMPLETE_SVC:
AD_READY_SVC:
EEPROM_READY_SVC:
ANA_COMA_SVC:
TWI_SVC:
SPM_READY_SVC:

reti

Hex2Bin:

ldi ZL,LOW ( ConvTbl<<1 )
ldi ZH,HIGH( ConvTbl<<1 )

andi r16,0x0f
clr r17

add ZL,r16
adc ZH,r17

lpm r16,Z
st Y+,r16
ret
.org 0x200
ConvTbl:
.db 0b00111111,0b00000110,0b01011011,0b01001111,0b01100110,0b01101101
.db 0b01111100,0b00000111,0b01111111,0b01100111,0b00001010,0b00001011
.db 0b00001100,0b00001101,0b00001110,0b00001111

ShowHex:
ldi r16,LOW(A)
ldi r17,high(A)

sts B,r16
sts B+1,r17
call Hex2Bin

ret
#101871
OK, each 7-segment digit is made up of 7 LEDs (well, 8, including the decimal point) - these will be set up "common anode" or "common cathode", (let's assume for the moment it's common cathode) so to made the digit show a certain number, you pull the common cathode low and drive some of the anodes high...

Now, since you've got four digits worth of display, those are probably going to be hooked up with corresponding anode lines from different digits hooked together. This means that you can display any number you like on one digit at a time, by pulling a single cathode low (to select the digit) and driving certain anodes high. The cathodes you're not using at a particular moment could be driven high (since LEDs are diodes, they won't light up if the voltage on the cathode is the same or higher than the voltage on the anode) or set as inputs. Driving them high is easier from a coding standpoint.

To display numbers on all four digit positions, you basically want to scan through the individual digits very fast - drive the display of a certain digit for a certain amount of time, then switch it off and display another one.

You might look at the sample C code from the Sparkfun clock kit as an example of how this all works in principle. I know you need to write this thing in assembly, but even in C you'll be seeing some familiar things (like setting or clearing individual bits in the port registers) and you should be able to get the basic idea.
#101900
I am not assembly saavy. I should pay more attention to it though, but the idea is simple, use this schematic, first of all.
Image

The code to drive this guy would be something like:
Code: Select all
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

void main(void) __attribute__((noreturn));

static const char hash[] = "~0my3[_p{";		// for common cathode, use this, for common anode, use the compliment
static uint8_t count = 0;

ISR(TIMER0_OVF_vect){
	// use this for common anode, for common cathode, use the compliment of PORTC
	PORTC <<= 1;
	if (PORTC == 16) PORTC = 1;
	switch (PORTC){
	case 1:
		PORTB = ~'~';			// technically, count/1000, but that is always 0.
		break;
	case 2:
		PORTB = ~hash[count/100];	// technically, (count/100)%10, but that's always count/100
		break;
	case 4:
		PORTB = ~hash[(count/10)%10];	// second to last significant digit
		break;
	case 8:
		PORTB = ~hash[count%10];			// least significant digit
	}
	// if at some point, you need a decimal point, then activate the following line.
	// PORTB |= _BV(7);			// for common cathode
	// PORTB &= ~_BV(7);		// for common anode
}

void main(void){
	//TODO: Setup timer0 and overflow interrupts.

	PORTC = 1;
	while(1){
		count++;		// will eventually overflow and roll back to 0
		_delay_ms(500);		// may not be an accurate delay, depending on F_CPU.
	}
}
The idea revolves around moving one bit in PORTC which will select which 7-segment display is on (pin will source current in my schematic). Then, the array hash[] contains the information of which pins in PORTB need to be driven low (sink current). I take the compliment of a character on the array and write that value into PORTB. When PORTC reaches 16, I've fed all 7 segment displays and need to return to the first one, thus PORTC = 1. Other than that, it is just a matter of setting up Timer0 so that it overflows whenever you need to (set prescaler and such).

Notice I haven't tested the select statements, they basically are designed to get one of the significant places from count. but at first glance they should work. The circuit is wired with an ATmega8, but your case should flow with the same principle.