wasnt sure where to post this so i stuck with my 8 & 16 bit forum, always good answers
In assembly I have an 8 bit register, GPREG
LDA #$6D ; which is decimal 109
STA GPREG
gives me 01101101
lets say i want an LED to turn on off according to that pattern
LSR GPREG
(check carry bit set LED on/off etc. for 8 bits)
now the led blinks in an order unique to "decimal 109"
how would i accomlpish this in C?
i have "decemial 109" or even "hex 6D"
i have:
byte b;
b = 109; // my variable type in this case is a byte, and i CANT change that
do i have to right an algorith creating an array?
for i = 0 to 7 {
if b divided by whatever*i has a remander or not theh pattern[i] = 0 or 1
} // sorry for ugly pseudo code
so now my "pattern[]" has 8 ints 0 and 1s, and matches my GPREG,
But is there an easier way?
byte b = 109;
if b.0
if b.1
if b.2 (bit 2 "third bit") is 0 then LED off
or something like that?
thanks in advance for the help
-mike
Hello Mike,
There is no need to use an array - you can also use a shift operation in C. The primary difference is that you do not have direct access to the carry flag (without use of a special "intrinsic" function), so the usual approach is to test the (LS) bit prior to doing the right shift.
The following assembly sub-routine will generate the LED sequence, and is what might be used in practice. I have made use of the stack for temporary storage, which is akin to using local variables in C.
LED EQU 0 ; PTAD0
; LED SEQUENCE OUTPUT
; On entry, ACC = LED pattern
; X = bit period (multiples of 10 ms)
LED_SEQ: PSHA ; Blink pattern (1,SP)
LDA #8 ; Bit counter
LS1: LSR 1,SP ; CF is current bit state
BCC LS2 ; Branch if off state
BSET LED,PTAD ; Turn LED on
BRA *+4 ; Skip next always
LS2: BCLR LED,PTAD ; Turn LED off
JSR WAIT ; X = multiples of 10 ms
DBNZA LS1 ; Loop for next state
AIS #1 ; Adjust stack pointer
RTS
The following C function should operate similarly to the above code.
#define LED PTAD_PTAD0 // Would usually be in a header file
void LED_seq( byte pattern, byte bit_time)
{
byte i; // Bit counter
for (i = 0; i << 8; i++) {
if (pattern & 1) // Test bit-0
LED = 1; // Turn LED on
else
LED = 0; // Turn LED off
pattern >>= 1; // Shift right
wait( bit_time); // Multiples of 10 ms
}
}
If you were to use a global variable for the bit pattern, rather than the function parameter, it is likely that the function would occupy more bytes, unless the global variable is explicitly placed within zero page RAM.
Regards,
Mac
#define LED PTAD_PTAD0 // Would usually be in a header filevoid LED_seq( byte pattern, byte bit_time){ byte i; // Bit counter for (i = 0; i << 8; i++) { if (pattern & 1) // Test bit-0 LED = 1; // Turn LED on else LED = 0; // Turn LED off pattern >>= 1; // Shift right wait( bit_time); // Multiples of 10 ms }}
this looks great mac, but (of course) i have a few questions...
so the "byte" type in C is like a register? as opposed to maybe int? you cant shift ints correct?
int foo;foo >>=1;
that wouldnt work right?
but we can operate on bytes like ints correct?
byte bar;bar = 50;bar = bar - 48;
this would make bar 2 correct? then it still stored as 0000010 correct?
next question is...
"pattern & 1" will always give you 1 or 0 correct? so why have the if statement?
cant you just do LED = pattern & 1; ???
last question...
i had been looking for somethign to "wait", so i see you have wait(7); that would wait 70ms correct??
is there a wait for microseconds (us)? in assembly i use subroutines with NOP.
in C though this has been more difficult. sometimes it seems i to a for loop or while loop and try to fill it with "asm (NOP);" but it seems that i can get the right amount of loops.
right now I use:
int a;a = 0;while (a < 565){ a++;}
to get a 500us delay. i know this is based off of the JM16's speed and clock settings, but it works, I just wandering if there is a wait() for microsecond intervals??
and of course THANK YOU THANK YOU for all of your help!!!
-mike
Hello Mike,
Within the header file for the MCU derivative, you should find the following entries -
typedef unsigned char byte;
typedef unsigned int word;
What this means is that you can use the byte data type in lieu of the standard data type of unsigned char. Similarly with using word in lieu of unsigned int. With C we refer to a "variable" as having a specific data type. The word "register" has a very specific meaning in C.
The first example that you give would require that variable foo be initialised prior to the shift operation.
foo >>= 1; // This is short-hand for
foo = foo >> 1;
Yes, you could use -
LED = pattern & 1;
Good observation! That is one I missed in attempting to demonstrate the equivalence of the assembly and C snippets.
I was not specific about the wait function, but you will obviously need one. While the looping method can be calibrated to produce the right amount of delay for a specific bus frequency, a better method is to make use of a timer module. An approach that is often used is to generate "tick" interrupts at regular intervals, typically 1 to 10 milliseconds. This can be used for general delay timing, provided you can tolerate a timing uncertainty of one tick interval - if the required timing parameter is N intervals, the actual delay will fall somewhere between N-1 and N intervals.
The chosen tick interval should not be too short, where the frequent execution of the ISR code would occupy a significant percentage of the processing time. With say, 500 microsecond interval and a 10MHz bus frequency, the number of cycles between interrupts would be 5000 - probably acceptable with short ISR code. However, a tick period of 50 microseconds would appear unacceptable in most instances.
The following code snippet assumes use of a TPM channel, using software compare mode, although there are other possible alteratives. Assume a 10 MHz bus frequency, and a TPM prescale factor of 4, the following ISR code is a possibility for a tick interval of 5ms.
#define INCRVAL 12500 // 5ms interval with 10MHz bus, TPM prescale 4
volatile word delay_cnt = 0; // volatile modifier is required for this global variable
__interrupt 9 void ISR_TPM1C0( void)
{
TPM1C0V += INCRVAL; // Next compare value
TPM1C0_CH0F = 0; // Clear flag
if (delay_cnt) delay_cnt--;
}
The delay function -
void wait( word delay)
{
delay_cnt = delay;
while (delay_cnt) // Wait for timeout
__RESET_WATCHDOG();
}
Regards,
Mac
GPREG = bitpattern;
for(i = 0; i < 8; i++)
{
if(GPREG & 0x80) bit_is_set();
GPREG <<= 1;
}