Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

binary coded modulation

Status
Not open for further replies.

MrDEB

Well-Known Member
while researching multiplexing a matrix and using shift registers (control a 8x8 matrix with 12 port pins) I stumbled across the BCM method of dimming comparing with PWM and see the advantage of using BCM over PWM. Here is a code as an example of using BCM (no I did not write this code). Anyone use this method??

#include <avr/io.h>
#include <avr/interrupt.h>
unsigned char pwmValues[8] = {0x00,0x02,0x04,0x08,0x10,0x20,0x40,0x80}; //Exponential Approximation
volatile unsigned char bcmBuffer[8];
unsigned char BCMtracker = 0;
void calcBCM(void) {
for (unsigned char i=0; i<8; i++){ //Cycle though each bit of each pwmValues
unsigned char tempValue = 0;
for (unsigned char j=0; j<8; j++){
if (pwmValues[j] & (1<<i)) tempValue |= (1<<j); //Always set MSB because we're shifting right
}
bcmBuffer = tempValue;
}
}
int main(void)
{
//Setup IO
DDRD = 0xFF;
PORTD = 0xFF;
//Prewind the Binary Coded Modulation buffer
calcBCM();
//PORTD = bcmBuffer[7];
//while(1){}
//Setup Timer
cli(); //disable all interrupts
TCCR0A |= (1<<WGM01); //Use CTC mode
TCCR0B |= (1<<CS02); //Start timer with 256 prescaler
TIMSK0 |= (1<<OCIE0A); //Enable the compare A interrupt
OCR0A = 0x01; //Set to compare on first timer tick
sei(); //enable all interrupts
while(1)
{
//Loop Forever
}
}
ISR(TIMER0_COMPA_vect) //Compare match interrupt handler
{
//Update LEDs
PORTD = bcmBuffer[BCMtracker];
//Set interrupt for next BCM delay value
if (BCMtracker == 0) OCR0A = 0x01;
else OCR0A <<= 1;
//Increment the BCM tracking index
BCMtracker ++;
BCMtracker &= 7; //Flip back to zero when it gets to 8
 
I'm lazy, or maybe I just like things that work. When I need to control a large number of LEDs, especially with different brightness levels, I farm the heavy lifting to a dedicated LED driver chip. Then my micro doesn't need to do busy work and I can concentrate on the task at hand.

Unless you need to run LEDs at different brightness levels, using hardware PWM is your best bet. Change the duty cycle when you want to change brightness and hardware takes care of the rest. There's no overhead to using hardware PWM - the chip takes care of it all.
 
Sorry about the code tags but when attempting to post a code using the insert code it does not work.
I agree with Jon about using PWM but if a need is desired to dim in excess or say 5 or six channels then the BCM might be a better bet.
Only time I could see needing to dim in excess of 5 or 6 channels is in a large led cube. After reviewing the information from
https://www.batsocks.co.uk/readme/art_bcm_1.htm I find several misinformation items such as Adrunio is better than microchip pics
 
.....I find several misinformation items such as Adrunio is better than microchip pics

If you're trying to use PWM, (I think you mean Arduino....by which you really mean...) AVR micros are better than 16F/18F PICs...they have more channels of hardware PWM channels than PIC's normal two.
 
The last I recall had four working in pairs.
 
From the link I posted it suggested that using BCM uses fewer resources but ??
I want to investigate this method further. As the link stated the BCM can output 255 levels of dim where as PWM only about 4 or 5??
When I was doing computer Christmas lights I recall using 74595 chips and the control boards are capable of 255 levels.
Another advantage of using BCM is it is not restricted to just a few port pins but most any port pin.
 
I have issues with code tag too, so I do it manually, like this:
*[*code*]* <--- remove the stars"*" to start tag
*[*/*code*]* <--- remove the stars"*" to stop tag

My most successful (in my eye) was using timer0 interrupt (on a PIC ), it emits a nice soft pleasant color while dim, and can still make it to full brightness, cant say it really frees resources though, in fact i now need to be cautious when doing other critical operations
PLUS im not using shift register, shifting dummy value out would work, but may take several clock ticks longer


Code:
#define _XTAL_FREQ 8000000

// some global variables here 

void runLED(unsigned char R, unsigned char G, unsigned char B)
{   
    if(R > dutyCounter){dummy &= 0b11111011;}else{dummy |= 0b00000100;}  
    if(G > dutyCounter){dummy &= 0b11110111;}else{dummy |= 0b00001000;}
    if(B > dutyCounter){dummy &= 0b11101111;}else{dummy |= 0b00010000;}
    if(dutyCounter > 250){dutyCounter = 0;}else{dutyCounter++;}
    dummy|= 0b00000010;   
    PORTC = dummy;                     
}

void interrupt  INTERRUPT()       //  where my interrupt occurs
{     
       if (T0IF == 1 & T0IE==1)     // check if timer0
    {            
       otherTimeCriticalOperations(more_globals_passed);  
       runLED(Red,Green,Blue);     // doit!
       TMR0 = 200;                          // reset timer0
    }                                      
    T0IF = 0;                                    // clear flag
}
 
One major issue is PWM outputs.
basic idea I am contemplating is an 8x8 led matrix that I scroll data across but the display shimmers or sparkles or what ever you want to call it.
hopefully utilize an 18lf2420 or 18f24K20 as the matrix will be coin cell powered. Using PWM I only have 2 port pins available if I interpreted the data sheet correctly thus the concept of BCM.
All 8 cathodes controlled by mosfets or transistors.
Another Idea I had was just blinking the cathodes at a variable rate, each cathode line at an independent rate. A crude method but might be easier to use.
It would be the KISS method. turn on each cathode line say DELAYUS(50 to 400) estimate
matrix w mosfets.jpg
 
You're going to use a coin cell to light 64 LEDs? You're battery life will be truly astonishing.

Mike.
 
not all the the same time. I designed n assembled 6 boards w/ 1-32mmx32mm matrix, 1 18f24k20, nine resistors all running on a coin cell battery. 6-10 hours run time. This design will be a DIY 8 x 8 matrix using smd, mosfets on the cathodes so I hopefully can make the display "twinkle" as the data is scrolled across.
Remember this is just a crossed fingers concept of an idea. Maybe it won't work but then maybe it will??
going to breadboard using transistors tomorrow then maybe??
 
This project may be going south as I have a basic pcboard layout but all canot fit into desired board size.
Thus I either need to go with smaller footprint components (using 1206 resistors and similar smd leds.
So a this juncture, we will end this thread.
NOTE the final project is led matrix ear rings or lapel buttons so size and weight have alo to consider.
 
Consider using an LED driver chip like a MAX7219. It will handle an 8x8 matrix with only one resistor and a 10uF capacitor. It uses an SPI interface so it requires reading and following the data sheet. You'd need to use a higher voltage power source.
 
And output compare will give shed loads more!!!
A couple of quick questions.

I cant work out how this would work, can you link to it or explain how this works please. I havnt stumbled upon this technique yet, sounds interesting, although this leads onto the next question.

I can see non light applications that benefit from many levels, but given that the eye wouldnt spot the difference between any two points (say level 1021 and 1022), how useful would it be adding a shed load more levels for light applications?

I am asking out of interest, the technique itself I can see alot of non light based applications for. Especially the piezo micro stage adjustment type application.
 
This is what John and me come up with...

C:
#include <xc.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define XMAX 605
#define XMIN 405
#define YMAX 605
#define YMIN 405

#define ABS(N) ( (N) >= 0 ? (N) : -(N) )
#pragma config LVP = OFF, BOREN = OFF,  FOSC = INTOSC, MCLRE = OFF, WDTE = OFF, PWRTE = OFF, PLLEN = OFF
volatile unsigned int RES;

void delayUs(int x)
   {
   x>>=3;                                                   // 125 * 8uS = 1000uS
   while(x--)                                               // a little bit out... 16 cylcles @ 0.5uS = 8uS
       {
       NOP();                                               // this means the lowest uS delay is 12uS ( including the call  and the shift )
       NOP();
       }
   }

void delayMs(int x)
   {
   while(x--)
       delayUs(1000);                                   //  Self explanitory
   }

void interrupt ISR(void)
   {
   if (TMR2IF)                                                   // End of period! start again
       {
       CCPR2L = RES & 0xFF;                       // set  CCP2
       CCPR2H = (RES>>8)&0xFF;               // finish position
       TMR1L = TMR1H = 0;                           // reset timer
       CCP2CON = 0x09;                               // turn on CCP2  pin
       TMR2IF = 0;                                           // Clear timer flag
       }
   else
       {
       TMR1L = TMR1H = 0;                           // Okay!  CCP interrupt..  reset timer
       CCP2CON = 0x0;                                   // Force Pin low
       CCP2IF = 0;                                           // Clear CCP interrupt
       }
   }

unsigned int GetFromAdc(unsigned char Channel)
   {
   unsigned int res;
   ADON = 1;                                                   // Start ADC module
   delayUs(100);
   GO = 1;
   while(GO);                                                   // wait for conversion
   res = (unsigned int)ADRESH<<8;
   res += ADRESL;
   //res<<=1;                                                   // if 11 bit is wanted!!
   return res;                                                   // 10 bit result
   }

void SetPwm(void)
   {
   RES = GetFromAdc(0);                           // Set duty
   RES += 0x0800;                                       // according to ADC reading on channel 0
   }                                                                   // Add in 1mS

void main(void)
   {
    OSCCON = 0x70;                                       // 8Mhz
   ADCON1 = 0xB0;                                       // set ADC TAD
   ANSELA = ANSELB = ANSELC = 0;   // All digital to start
   TRISA = TRISC = 0x0;                               // Prep ports
   TRISB = 0xAF;
   T2CON = 0x4E;                                       // Timer2 on
   PR2 = 250;                                               //
   TMR2IE = 1;                                               // interrupt on timer 2 required
   INTCON = 0xC0;                                       // GIE and PEIE on
   T1CON = 1;                                               // Turn on timer 1
   CCP2SEL = 1;
   CCP2IE = 1;                                               // interrupt on CCP match required!!
   TMR1L = TMR1H = 0;                               // reset timer
   ANSELA = 0x01;                                       // AN0 selected
   ADCON1 = 0xb0;                                       // Again!! Christ knows why!!
   CCPR2L = 0;
   CCPR2H = 0x08;                                       // start at 1mS
   while(1)
       {
       SetPwm();                                               // Super loop and read pot!
       }

   }

If working with light then there is a pwm conversion table ( I think Roman Black has one on his web site ) will give a linear dimmer...
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top