I'm working on a project that requires a series of PWM pulses at 56Khz. A very kind person out there gave me a chunk of code that he said worked for him. I've tested it, and it does work for my application, but I'd really like to be able to understand all of it. I understand most of it, but the timer initializations and the actual transmission elude me.
I fully grasp the concept of how the counter/timers are used to generate the PWM signal (you are constantly counting upward until you hit a compare marker at which point something is toggled "on", and it stays on until you hit the end of your count and everything is toggled "off"), but I haven't been able to penetrate what these timer variables are actually representing to understand where those steps are occurring. Here's the code:
#define IR_PWM_FREQUENCY 56 // What frequency is the IR
#define TX_IO_Pin 3 // Pin to send data on
#if IR_PWM_FREQUENCY == 56
#define PWM_DELAY 13
#define IR_CLOCK_RATE 56000
#endif
int switchState = 0;
void setup() {
// Serial.begin(9600);
MT5_TX_init();
pinMode(2,INPUT);
}
void loop() {
switchState = digitalRead(2);
if (switchState == LOW) {
digitalWrite(TX_IO_Pin,LOW);
}
else {
MT5_TX_shot(1,25,9);
delay(250);
}
}
void MT5_TX_init(){
// toggle on compare, clk/1
TCCR2A = (1 << WGM21);
TCCR2B = (1 << CS20);
OCR2A = (F_CPU/(IR_CLOCK_RATE*2L)-1);
OCR2B = OCR2A; // / 2;
pinMode(TX_IO_Pin, OUTPUT);
digitalWrite(TX_IO_Pin, LOW);
}
void MT5_TX(long uSecs){
TCCR2A |= (1 << COM2B0);
delayMicroseconds(uSecs); //PWM_DELAY - 3);
TCCR2A &= ~(1 << COM2B0);
}
void MT5_TX_header(){
MT5_TX(2400);
delayMicroseconds(600);
}
void MT5_TX_logic1(){
MT5_TX(1200);
delayMicroseconds(600);
}
void MT5_TX_logic0(){
MT5_TX(600);
delayMicroseconds(600);
}
void MT5_TX_byte(byte data) {
for (byte mask = 10000000; mask > 0; mask >>= 1) {
if (data & mask) {
MT5_TX_logic1();
}
else {
MT5_TX_logic0();
}
}
}
void MT5_TX_shot(byte teamID, byte playerID, byte damage) {
MT5_TX_header();
MT5_TX_byte(playerID);
MT5_TX_byte((teamID << 6) + (damage << 2)); // Shifting the values to the front 6 bits of the byte
}
Obviously this is an implementation of the MilesTag laser tag protocol. I understand everything here except the most critical 2 functions -- MT5_TX_init(), and MT5_TX(). In fact, I rewrote the MT5_TX_shot and MT5_TX_byte functions in a way I could better understand them. Mostly, I'm just trying to figure out where the values are coming from for the TCCR2A, TCCR2B, OCR2A, OCR2B, WGM21, CS20, and COM2B0 variables. I understand that they're pre-defined registers on the chip, but I don't exactly know what that means, and I don't know what these operations do to the registers.
I would also love it if someone could explain the formula for the OCR2A variable. I realize that's probably got something to do with the pre-scaler and where to set the compare register, but I just can't figure out how that works.
If anyone can help explain this, or if anyone can direct me toward a good tutorial that's mostly on-topic with what I'm trying to do here, I would be most appreciative! While it's working now for the ATmega328 chip, I'd love to understand this well enough to implement it on any microcontroller in the future as needed. Thank you!