
PIC16F1503. Wheelbarrow for pumping - 2. Light
- Tutorial
It used to be about sound .
I left the last post unfinished. If you remember, I couldn’t manage to pick up “the very sound”. Attempts to pick up “numbers by intuition” turned out to be much worse than the usual “piu-piu” ... On the one hand, anyway - there is no sound from the Chinese tweeter, but on the other hand - “unclean work, low class”. Again, drive a clock frequency of 16 MHz for this ...

In general, I did something wrong somewhere. Arranged the next evening, an educational program on music and its literacy raised even more questions than before (it seems like there is a sharp sharp, but no sharp sharp, but instead E flat?). But I’m not accustomed to “take Japanese by the training manual,” so I continued to understand. At the same time, the customer discussed the change in the specification (a familiar picture, isn’t it?), Which consisted of adding a “bottom illumination”. To my timid attempts to say that this is actually a police car, the answer was received that it was a police car in the Negro quarter ...
For a start, I decided to finish off the sound. I changed the frequencies and PWM, set the divider to 1 by 255, got the frequencies of 7692 Hz and 62 Hz. The range has changed a little, but still - quite.
And then something pulled me to measure the frequency with the divider 128. I was expecting to get something like (7692-62) / 2 = 3815Hz, but for some reason I got only 125 ... And then me, as my favorite programmers in deer sweaters , it dawned on: who said that the frequency-divider relationship is linear? A couple of extra measurements showed that I was absolutely right. A little trachytibidoch with an oscilloscope and an exel gave such a beautiful Hz-Timer picture (the originals, as usual, in the archive at the end of the post):

Now I realized why my sounds were so terrible. Plus, in the comments, they remembered about doorbells, where in 2KB ROM tunes were thrust in ... When you know what to look for, it is fast.
The first (like) such a scheme was published in the journal Radio, 92 year old, 8th issue. There was a chic (for me) tablet

And on the next page - the firmware itself. Even more guglage and we find the "Amateur Radio", 93, February. There is exactly the same principle, but there are more melodies.
We charge the Excel again (in the archive on the second tab) and translate the delays from “hardware” to “software”.
Add some code
And cheers! From the Chinese tweeter you can hear quite recognizable sounds that even my ears do not offend. In principle, we can be proud of ourselves - on the new element base, we repeated the 20-year-old scheme on the “logic”. So even if the machine is not playable, it will always be possible to remake it at the doorbell :)
In general, while the process of searching for the best “wow-wow” continues, but in principle we have closed the sound problem. We turn to the light.
As I wrote in the first post, the native LEDs were blue and very bright. Plus, I was outraged that the blue light shines through the red filter and violates all harmony. So you need to change.
I took out a red LED from the stash, turned it on. The first problem: the brightness is different. Blue is very bright. We change to "from stash" - it’s still different. Of course, you can muffle additional resistors, but it's too simple. Finally I got to the RGB LED and a miracle happened! It shines with all colors with the same brightness. In principle, it is not surprising, because it costs like fifty of the "cheapest".
It was decided, I take four RGB LEDs for all needs (red and blue parts of the chandelier, headlights and bottom). My LEDs have a common cathode, so I need 3 (RGB) * 4 (pieces) - 12 legs for control. Again, the problem: the microcontroller has only 12 (generally 14, but two power) legs, one of which is allocated exclusively to the “input” (it resets on it) and one we took under the “music”. And somewhere else you need to hang up the switch and leave the reserve.
Usually, in such cases they’re doing just that: they take and install some kind of “port expander”. The most common option is the shift register type 74HC595. But putting the second chip side by side is a bust and a complete budget overrun. If all projects do this, then nothing will remain on the pies ... And we at studiovsemoe.com really love to eat :)
Therefore, I will go the other way and do everything by the controller. I spread the legs (all to the output) like this

And connect the LEDs like this (as usual, the complete circuit in the archive)

In the circuit I “split” each LED into three separate ones, so that the principle of operation would be understood. Well, for some reason, the resistors stuck at 10k, although in reality they are 200-300 Ohms. As a result, we have a 4x3 LED matrix.
Attention: this scheme is suitable only for 1-2-3 LEDs. If you plan to connect more - use a special driver like L298 - otherwise the current through the output of the microcircuit will be too large.
Add some code
Here we set the legs C0-C2 to unity, and C3-C5 and A5 to zero. If everything is assembled correctly, then you should light up all the LEDs "white light".
What happened As you know, current flows from a place with high potential to a place with low. And on one leg we have 1 (or + 3V), and on the other legs - 0. So the LEDs light up. If on those and those legs file 0 or 1 - nothing will burn. By the way, the versatility of the circuit also emerges from here - if you have LEDs not with a common cathode, like mine, but with a common anode, then in the code you just need to change 0 to 1 and it will work.
As a result, combining the state of the legs C0-C2, we can choose the color of the glow, and others choose which LED lights out of 4, so instead of the original 12 legs cost 7y. Not very cool (with a shift register you can do 2), but for our purposes more than enough.
But at least two of our LEDs will have to be lit at the same time with different colors (for example, a chandelier and a headlight, a headlight and a bottom). Here I use a trick as old as the world: I will quickly and quickly switch between LEDs and turn on the desired colors. If done quickly enough, the eye will not notice a flicker.
We try to blink colors (I think the meaning can be understood from the notation)
And we see how the LEDs flash beautifully, sorting through the colors ...
In principle, you can rewrite it to work directly with the port - it's easier.
What is the difference? The difference is. that the first option takes (with all the bindings) 89 bytes, and the second 81. 8 bytes of the difference out of the blue. Well, the second one works faster :)
If you don’t understand, then the design
Completely similar
Where are the cons? The disadvantages are that on some controllers the most significant bits can be given for something useful, and we shove everything there and climb with dirty hands ...
Where is the other minus? Another minus is that we again have to deal with "trepidation." Well, this is an unworthy thing for talents like us. Nekhay piece of iron is engaged in it.
We have a timer that is responsible for the sound. No, we won’t touch him, but we touch his neighbors. For a change we will take TIM1
What is its difference from TIM2? Firstly, greater accuracy - if TIM2 has the range divided into 255 parts, then here it is divided into 65535. That means you can get into the frequency more precisely. Secondly, he is not attached to anything and nothing is attached to him. And finally, its output can be brought to the foot of the microcontroller. We need almost none of this, so we just allow it interrupts and in the interrupt handler we will blink LEDs.
In general, we configure it like this. The

main thing here is to pay attention to the inclusion of interrupts and the call of each interruption of the function (the bottom line).
Now in the tmr1.c file at the very end there is a function that will be called every 64 microseconds (By the way, due to the wide capabilities (pay attention to the Reload Value field) we can change this value to “once every 4 seconds”).
Since we love extensible and configurable code, we add two files to the project that are responsible for the operation of
led.h LEDs :
Then in led.c we add the “work” with color
And in the interrupt handler code
Finally, there is nothing left to do but write verification code.
We compile, run and get a complete bummer. Nothing flashes and does not overflow. Why? I will save you from thinking and searching. Because we set to generate an interrupt every 64 microseconds. And the processor clocked at 62 kilohertz. That is, 1 clock cycle takes 16 microseconds. Does anyone believe that the processor is capable of executing all the piling up of commands drawn above in 4 clock cycles? So I do not believe. As a result, the microcontroller hangs forever in the timer interrupt handler.
By logical reasoning (in fact, banal selection) , we find out that one interrupt is processed on the order of 3 milliseconds (or FFC0 in the timer counter).
What is visible? Color-changing LEDs that flicker are visible. And "pure white" is not visible. What is the reason? The reason is time, or rather, the frequency. How do LEDs work for us now? 3ms is on - 9ms is not on. PWM frequency of 80 hertz with 25% coverage. From experience, I know that the eye ceases to notice a PWM somewhere from 200 hertz.
What to do? The easiest way out is to raise the frequency. Sooner or later, the eye will cease to notice flicker. Whatever sound frequencies “float away” from us, we look at the possible values of the preliminary divider at TIM2 - 1: 1, 1: 4, 1:16 and 1:64. We now have a frequency of 62KHz, which means we can set 62 * 4 = 250KHz, 62 * 16 = 1MHz or 62 * 64 = 4MHz.
The best is the enemy of the good, so I set the frequency of the microcontroller to 1 MHz, change the divider to 1:16 and fill the firmware again. Hooray! The flicker is gone.

True, some colors ... not really. No, these are not the glitches of the iPhone with which I took the photo. It is actually only red like red (in fact there should be white-red-blue-green). And the switch is kind of sluggish, completely unlike the required 50ms.
What is the problem? Again, the villainous physicist set us up on the bandwagon: in 180 microseconds (3ms / 16) the LED does not have time to “flare up”. The result is what is visible in the photo.
What can be done? Well, again, the “forehead” solution begs to poke delays after the LED is lit, so that it can catch fire. In principle, the solution is good. But it’s better to give the programmer a head start.
What for? Let's do a thought experiment and add 2 more LEDs. If we used to have PWM with 25% coverage, now it will be 16%. Adding four more will reduce to 10%. This is how it will be necessary to pick up the frequency and how to sex with delays, so that the resulting design works?
Therefore, we look again at the algorithm. It now looks like this
- turn on the current LED and turn off the others
- does the current LED have something in the red channel? if yes, then turn on the red channel, otherwise turn it off
- does the current LED have something in the green channel? if yes, then turn on the green channel, otherwise turn it off
- does the current LED have something in the blue channel? if yes, then turn on the blue channel, otherwise turn off
And now we are going to cram more delays for each LED ... again we get a flicker, again raise the frequency. Complete unsuitability and sobbing in a dark corner are waiting for us if we don’t think of a way out :)
Since I don’t want to sob, I change the algorithm to the next one
- Turn on channel N (red, green, blue)
- In the M LED (0,1,2,3 , ...) should the current channel H be lit? If yes, then turn it on. If not, then turn it off.
- Repeat the cycle for M
- Let's wait for the last LED to turn on.
- Repeat the cycle for H
It seems that the difference is not big, but feel the difference: for any number of LEDs, the PWM for them will be 33% full. We check.
Code for one channel (the rest are completely similar). Definitions can also be seen in the full version, but I think the names will be clear.
And we admire.

This is not so well visible in the photo, but in reality, green turned green and blue turned blue.
Well now we change to "almost like in the finale."
The chandelier winks! The headlight is shining! And the bottom is all so green! In general, complete and unconditional success in our endeavors. We are cool! What else is needed for motivation? :) Get a little silence :) The preliminary display of the results to the customer received full approval and the allocation of additional volumes of resources for work (“dad, I'll be very quiet for two more nights” and other parental blackmail)
Bonus for this business: almost the standard NYPD blink
The most thoughtful question for a showdown: why does __delay_ms (_X_) in this case pause 5 times more than the set _X_ ms?
But that is not all. Next, we consider the most important question: how to turn off this business?
As usual, a complete set of everything lies here multik.org/pic/policelight.rar
I left the last post unfinished. If you remember, I couldn’t manage to pick up “the very sound”. Attempts to pick up “numbers by intuition” turned out to be much worse than the usual “piu-piu” ... On the one hand, anyway - there is no sound from the Chinese tweeter, but on the other hand - “unclean work, low class”. Again, drive a clock frequency of 16 MHz for this ...

In general, I did something wrong somewhere. Arranged the next evening, an educational program on music and its literacy raised even more questions than before (it seems like there is a sharp sharp, but no sharp sharp, but instead E flat?). But I’m not accustomed to “take Japanese by the training manual,” so I continued to understand. At the same time, the customer discussed the change in the specification (a familiar picture, isn’t it?), Which consisted of adding a “bottom illumination”. To my timid attempts to say that this is actually a police car, the answer was received that it was a police car in the Negro quarter ...
For a start, I decided to finish off the sound. I changed the frequencies and PWM, set the divider to 1 by 255, got the frequencies of 7692 Hz and 62 Hz. The range has changed a little, but still - quite.
And then something pulled me to measure the frequency with the divider 128. I was expecting to get something like (7692-62) / 2 = 3815Hz, but for some reason I got only 125 ... And then me, as my favorite programmers in deer sweaters , it dawned on: who said that the frequency-divider relationship is linear? A couple of extra measurements showed that I was absolutely right. A little trachytibidoch with an oscilloscope and an exel gave such a beautiful Hz-Timer picture (the originals, as usual, in the archive at the end of the post):

Now I realized why my sounds were so terrible. Plus, in the comments, they remembered about doorbells, where in 2KB ROM tunes were thrust in ... When you know what to look for, it is fast.
The first (like) such a scheme was published in the journal Radio, 92 year old, 8th issue. There was a chic (for me) tablet

And on the next page - the firmware itself. Even more guglage and we find the "Amateur Radio", 93, February. There is exactly the same principle, but there are more melodies.
We charge the Excel again (in the archive on the second tab) and translate the delays from “hardware” to “software”.
Add some code
// come cool sound
const uint8_t m1[31]={49,49,52,52,58,58,58,58,38,38,28,52,52,52,52,52,52,52,52,38,38,36,38,36,38,52,52,49,49,49,49};
const uint8_t m2[31]={49,42,38,38,49,42,38,42,49,52,58,52,49,42,52,65,49,42,38,38,49,42,38,42,49,52,58,42,49,42,52};
// play like this
uint8_t c;
for(c=0;c<31;c++)
{
PWM3_LoadDutyValue(m1[c]*2);
TMR2_LoadPeriodRegister(m1[c]);
__delay_ms(120);
}
And cheers! From the Chinese tweeter you can hear quite recognizable sounds that even my ears do not offend. In principle, we can be proud of ourselves - on the new element base, we repeated the 20-year-old scheme on the “logic”. So even if the machine is not playable, it will always be possible to remake it at the doorbell :)
In general, while the process of searching for the best “wow-wow” continues, but in principle we have closed the sound problem. We turn to the light.
As I wrote in the first post, the native LEDs were blue and very bright. Plus, I was outraged that the blue light shines through the red filter and violates all harmony. So you need to change.
I took out a red LED from the stash, turned it on. The first problem: the brightness is different. Blue is very bright. We change to "from stash" - it’s still different. Of course, you can muffle additional resistors, but it's too simple. Finally I got to the RGB LED and a miracle happened! It shines with all colors with the same brightness. In principle, it is not surprising, because it costs like fifty of the "cheapest".
It was decided, I take four RGB LEDs for all needs (red and blue parts of the chandelier, headlights and bottom). My LEDs have a common cathode, so I need 3 (RGB) * 4 (pieces) - 12 legs for control. Again, the problem: the microcontroller has only 12 (generally 14, but two power) legs, one of which is allocated exclusively to the “input” (it resets on it) and one we took under the “music”. And somewhere else you need to hang up the switch and leave the reserve.
Usually, in such cases they’re doing just that: they take and install some kind of “port expander”. The most common option is the shift register type 74HC595. But putting the second chip side by side is a bust and a complete budget overrun. If all projects do this, then nothing will remain on the pies ... And we at studiovsemoe.com really love to eat :)
Therefore, I will go the other way and do everything by the controller. I spread the legs (all to the output) like this

And connect the LEDs like this (as usual, the complete circuit in the archive)

In the circuit I “split” each LED into three separate ones, so that the principle of operation would be understood. Well, for some reason, the resistors stuck at 10k, although in reality they are 200-300 Ohms. As a result, we have a 4x3 LED matrix.
Attention: this scheme is suitable only for 1-2-3 LEDs. If you plan to connect more - use a special driver like L298 - otherwise the current through the output of the microcircuit will be too large.
Add some code
LATCbits.LATC0 = 1; // RED
LATCbits.LATC1 = 1; // GREEN
LATCbits.LATC2 = 1; // BLUE
LATCbits.LATC3 = 0;
LATCbits.LATC4 = 0;
LATCbits.LATC5 = 0;
LATAbits.LATA5 = 0;
Here we set the legs C0-C2 to unity, and C3-C5 and A5 to zero. If everything is assembled correctly, then you should light up all the LEDs "white light".
What happened As you know, current flows from a place with high potential to a place with low. And on one leg we have 1 (or + 3V), and on the other legs - 0. So the LEDs light up. If on those and those legs file 0 or 1 - nothing will burn. By the way, the versatility of the circuit also emerges from here - if you have LEDs not with a common cathode, like mine, but with a common anode, then in the code you just need to change 0 to 1 and it will work.
As a result, combining the state of the legs C0-C2, we can choose the color of the glow, and others choose which LED lights out of 4, so instead of the original 12 legs cost 7y. Not very cool (with a shift register you can do 2), but for our purposes more than enough.
But at least two of our LEDs will have to be lit at the same time with different colors (for example, a chandelier and a headlight, a headlight and a bottom). Here I use a trick as old as the world: I will quickly and quickly switch between LEDs and turn on the desired colors. If done quickly enough, the eye will not notice a flicker.
We try to blink colors (I think the meaning can be understood from the notation)
LATCbits.LATC3 = 0;
LATCbits.LATC4 = 0;
LATCbits.LATC5 = 0;
LATAbits.LATA5 = 0;
while(1)
{
LATCbits.LATC0 = 1;
LATCbits.LATC1 = 0;
LATCbits.LATC2 = 0;
__delay_ms(50);
LATCbits.LATC0 = 0;
LATCbits.LATC1 = 1;
LATCbits.LATC2 = 0;
__delay_ms(50);
LATCbits.LATC0 = 0;
LATCbits.LATC1 = 0;
LATCbits.LATC2 = 1;
__delay_ms(50);
}
And we see how the LEDs flash beautifully, sorting through the colors ...
In principle, you can rewrite it to work directly with the port - it's easier.
while(1)
{
LATC=0b00000001;
__delay_ms(50);
LATC=0b00000010;
__delay_ms(50);
LATC=0b00000100;
__delay_ms(50);
}
What is the difference? The difference is. that the first option takes (with all the bindings) 89 bytes, and the second 81. 8 bytes of the difference out of the blue. Well, the second one works faster :)
If you don’t understand, then the design
LATC=0b00000001;
Completely similar
LATCbits.LATC0 = 1;
LATCbits.LATC1 = 0;
LATCbits.LATC2 = 0;
LATCbits.LATC3 = 0;
LATCbits.LATC4 = 0;
LATCbits.LATC5 = 0;
LATCbits.LATC6 = 0;
LATCbits.LATC7 = 0;
Where are the cons? The disadvantages are that on some controllers the most significant bits can be given for something useful, and we shove everything there and climb with dirty hands ...
Where is the other minus? Another minus is that we again have to deal with "trepidation." Well, this is an unworthy thing for talents like us. Nekhay piece of iron is engaged in it.
We have a timer that is responsible for the sound. No, we won’t touch him, but we touch his neighbors. For a change we will take TIM1
What is its difference from TIM2? Firstly, greater accuracy - if TIM2 has the range divided into 255 parts, then here it is divided into 65535. That means you can get into the frequency more precisely. Secondly, he is not attached to anything and nothing is attached to him. And finally, its output can be brought to the foot of the microcontroller. We need almost none of this, so we just allow it interrupts and in the interrupt handler we will blink LEDs.
In general, we configure it like this. The

main thing here is to pay attention to the inclusion of interrupts and the call of each interruption of the function (the bottom line).
Now in the tmr1.c file at the very end there is a function that will be called every 64 microseconds (By the way, due to the wide capabilities (pay attention to the Reload Value field) we can change this value to “once every 4 seconds”).
void TMR1_ISR(void)
{
// Clear the TMR1 interrupt flag
PIR1bits.TMR1IF = 0;
TMR1H = (timer1ReloadVal >> 8);
TMR1L = timer1ReloadVal;
// Add your TMR1 interrupt custom code
}
Since we love extensible and configurable code, we add two files to the project that are responsible for the operation of
led.h LEDs :
// basic colors
#define RED 1
#define GREEN 2
#define BLUE 4
#define OFF 0
// set led N to color C
void setLed(uint8_t n,uint8_t c);
// get color of led N
uint8_t getLed(uint8_t n);
extern volatile uint8_t lc[4];
// How LED connected
#define _LED1_ LATCbits.LATC3
#define _LED2_ LATCbits.LATC4
#define _LED3_ LATCbits.LATC5
#define _LED4_ LATAbits.LATA5
#define _LEDR_ LATCbits.LATC0
#define _LEDG_ LATCbits.LATC1
#define _LEDB_ LATCbits.LATC2
Then in led.c we add the “work” with color
volatile uint8_t lc[4]; // current led colors 0 - off
void setLed(uint8_t n,uint8_t c)
{
lc[n]=c;
}
uint8_t getLed(uint8_t n)
{
return lc[n];
}
And in the interrupt handler code
switch(current_led)
{
case 0:
_LED1_=0;
_LED2_=1;
_LED3_=1;
_LED4_=1;
break;
case 1:
_LED1_=1;
_LED2_=0;
_LED3_=1;
_LED4_=1;
break;
case 2:
_LED1_=1;
_LED2_=1;
_LED3_=0;
_LED4_=1;
break;
case 3:
_LED1_=1;
_LED2_=1;
_LED3_=1;
_LED4_=0;
break;
}
if((lc[current_led]&RED)==RED)
_LEDR_=1;
else
_LEDR_=0;
if((lc[current_led]&GREEN)==GREEN)
_LEDG_=1;
else
_LEDG_=0;
if((lc[current_led]&BLUE)==BLUE)
_LEDB_=1;
else
_LEDB_=0;
current_led++;
if(current_led>3) current_led=0;
Finally, there is nothing left to do but write verification code.
setLed(0,RED);
setLed(1,GREEN);
setLed(2,BLUE);
setLed(3,RED+GREEN+BLUE);
__delay_ms(50);
setLed(1,RED);
setLed(2,GREEN);
setLed(3,BLUE);
setLed(0,RED+GREEN+BLUE);
__delay_ms(50);
setLed(2,RED);
setLed(3,GREEN);
setLed(0,BLUE);
setLed(1,RED+GREEN+BLUE);
__delay_ms(50);
setLed(3,RED);
setLed(0,GREEN);
setLed(1,BLUE);
setLed(2,RED+GREEN+BLUE);
__delay_ms(50);
We compile, run and get a complete bummer. Nothing flashes and does not overflow. Why? I will save you from thinking and searching. Because we set to generate an interrupt every 64 microseconds. And the processor clocked at 62 kilohertz. That is, 1 clock cycle takes 16 microseconds. Does anyone believe that the processor is capable of executing all the piling up of commands drawn above in 4 clock cycles? So I do not believe. As a result, the microcontroller hangs forever in the timer interrupt handler.
By logical reasoning (in fact, banal selection) , we find out that one interrupt is processed on the order of 3 milliseconds (or FFC0 in the timer counter).
What is visible? Color-changing LEDs that flicker are visible. And "pure white" is not visible. What is the reason? The reason is time, or rather, the frequency. How do LEDs work for us now? 3ms is on - 9ms is not on. PWM frequency of 80 hertz with 25% coverage. From experience, I know that the eye ceases to notice a PWM somewhere from 200 hertz.
What to do? The easiest way out is to raise the frequency. Sooner or later, the eye will cease to notice flicker. Whatever sound frequencies “float away” from us, we look at the possible values of the preliminary divider at TIM2 - 1: 1, 1: 4, 1:16 and 1:64. We now have a frequency of 62KHz, which means we can set 62 * 4 = 250KHz, 62 * 16 = 1MHz or 62 * 64 = 4MHz.
The best is the enemy of the good, so I set the frequency of the microcontroller to 1 MHz, change the divider to 1:16 and fill the firmware again. Hooray! The flicker is gone.

True, some colors ... not really. No, these are not the glitches of the iPhone with which I took the photo. It is actually only red like red (in fact there should be white-red-blue-green). And the switch is kind of sluggish, completely unlike the required 50ms.
What is the problem? Again, the villainous physicist set us up on the bandwagon: in 180 microseconds (3ms / 16) the LED does not have time to “flare up”. The result is what is visible in the photo.
What can be done? Well, again, the “forehead” solution begs to poke delays after the LED is lit, so that it can catch fire. In principle, the solution is good. But it’s better to give the programmer a head start.
What for? Let's do a thought experiment and add 2 more LEDs. If we used to have PWM with 25% coverage, now it will be 16%. Adding four more will reduce to 10%. This is how it will be necessary to pick up the frequency and how to sex with delays, so that the resulting design works?
Therefore, we look again at the algorithm. It now looks like this
- turn on the current LED and turn off the others
- does the current LED have something in the red channel? if yes, then turn on the red channel, otherwise turn it off
- does the current LED have something in the green channel? if yes, then turn on the green channel, otherwise turn it off
- does the current LED have something in the blue channel? if yes, then turn on the blue channel, otherwise turn off
And now we are going to cram more delays for each LED ... again we get a flicker, again raise the frequency. Complete unsuitability and sobbing in a dark corner are waiting for us if we don’t think of a way out :)
Since I don’t want to sob, I change the algorithm to the next one
- Turn on channel N (red, green, blue)
- In the M LED (0,1,2,3 , ...) should the current channel H be lit? If yes, then turn it on. If not, then turn it off.
- Repeat the cycle for M
- Let's wait for the last LED to turn on.
- Repeat the cycle for H
It seems that the difference is not big, but feel the difference: for any number of LEDs, the PWM for them will be 33% full. We check.
Code for one channel (the rest are completely similar). Definitions can also be seen in the full version, but I think the names will be clear.
_LEDR_=_LEDON_;
if ((lc[0] & RED) == RED)
_LED1_ = _LEDOFF_; // INVERTED!
else
_LED1_ = _LEDON_;
if ((lc[1] & RED) == RED)
_LED2_ = _LEDOFF_; // INVERTED!
else
_LED2_ = _LEDON_;
if ((lc[2] & RED) == RED)
_LED3_ = _LEDOFF_; // INVERTED!
else
_LED3_ = _LEDON_;
if ((lc[3] & RED) == RED)
_LED4_ = _LEDOFF_; // INVERTED!
else
_LED4_ = _LEDON_;
for(leds=0;leds<80;leds++) current_led++;
_LEDR_=_LEDOFF_;
And we admire.

This is not so well visible in the photo, but in reality, green turned green and blue turned blue.
Well now we change to "almost like in the finale."
setLed(3,RED+GREEN+BLUE);
setLed(2,GREEN);
setLed(0,RED);
__delay_ms(100);
setLed(0,OFF);
setLed(1,BLUE);
__delay_ms(100);
setLed(1,OFF);
The chandelier winks! The headlight is shining! And the bottom is all so green! In general, complete and unconditional success in our endeavors. We are cool! What else is needed for motivation? :) Get a little silence :) The preliminary display of the results to the customer received full approval and the allocation of additional volumes of resources for work (“dad, I'll be very quiet for two more nights” and other parental blackmail)
Bonus for this business: almost the standard NYPD blink
uint8_t c;
setLed(3, RED + GREEN + BLUE);
setLed(2, GREEN);
while (1) {
setLed(0, RED);
setLed(1, OFF);
__delay_ms(40);
for (c = 0; c < 10; c++) {
setLed(0, OFF);
__delay_ms(10);
setLed(0, RED);
__delay_ms(10);
}
setLed(1, BLUE);
setLed(0, OFF);
__delay_ms(40);
for (c = 0; c < 10; c++) {
setLed(1, OFF);
__delay_ms(10);
setLed(1, BLUE);
__delay_ms(10);
}
}
The most thoughtful question for a showdown: why does __delay_ms (_X_) in this case pause 5 times more than the set _X_ ms?
But that is not all. Next, we consider the most important question: how to turn off this business?
As usual, a complete set of everything lies here multik.org/pic/policelight.rar