What I want:
To be able to toggle the OCR1A pin (PB1) on/off after x microseconds using counter/timer to have a pseudo 50% PWM.
Hardware/wiring:
Atmega328P-PU bootloaded and working (tested with blink sketch).
16Mhz crystal external.
Oscillocope probe wire on IC pin 15 and GND.
10k resistor between reset and +5V.
What I have done (using the datasheet and some swearing):
/*
TOP
The counter reaches the TOP when it becomes equal to the highest value in the count
sequence. The TOP value can be assigned to be one of the fixed values: 0x00FF, 0x01FF,
or 0x03FF, or to the value stored in the OCR1A or ICR1 Register. The assignment is
dependent of the mode of operation.
*/
// the setup function runs once when you press reset or power the board
void setup() {
CLKPR = 0;
// Clock Pre-scale Register = 0. Clock division factor = 1 ie. 16Mhz external crystal.
// Data sheet -> Table 6-17 "Clock Prescalar Select". Using NO PRESCALAING...i.e. at 16Mhz.
TCCR1A = 0
/*
In CTC mode the counter is cleared to zero when the counter value (TCNT1)
matches either the OCR1A (WGM13:0 = 4)
The OCR1A or ICR1 define the top value for the counter
WGMbits 13:12:11:10 as 0:1:0:0 (mode 4) supposedly is:
"Mode = CTC, TOP = OCR1A, update = immediate, TOV1 flag set on MAX"
I assumed once the counter hits the value in OCR1A, the pin toggle would occur...and CTC resets the counter...
COM1A0 and COM1A1 bits as 1:0 should give "Toggle OC1A/OC1B on Compare Match."
*/
| (1 << COM1A0) //(COM1A0 and COM1A1) indicate what to do when comparator == counter
| (0 << COM1A1) // When A0 is 1 and A1 is 0, the pin is toggled on a compare (Low->High or High->Low)
| (1 << WGM12) // CTC bit in WGM13:10
| (0 << WGM11) // Set to 0. WGM13:10 = 0100 so mode 4 operation.
| (0 << WGM10) // Set to 0. WGM13:10 = 0100 so mode 4 operation.
;
TCCR1B = 0 // Timer/Counter1 Control Register B
| (0 << ICNC1) // No noise cancelation...not an external counter on ICP1.
| (0 << ICES1) // Falling edge trigger on ICP1...but not in use so meh.
| (0 << WGM13) // Set to 0. WGM13:10 = 0100 so mode 4 operation.
| (0 << CS12)//Prescaler Divide bits...
| (1 << CS11)//Prescaler Divide bits...
| (0 << CS10)//Prescaler Divide bits...010 = Divide clock from prescalar by 8..."2Mhz" = 0.5uS per tick. (CLKi/o used)
;
DDRB = 0
| (1 << PB1); //Set PB1 as OUTPUT (Pin 15 on IC / "OC1A"/ IDE 9 /PWM)
OCR1A = 12; // Counter Max...clock cycles before pin is toggled.
/* Output Compare Registers (OCR1A)
The double buffered Output Compare Registers (OCR1A) are compared with the Timer/Counter value at all time.
The result of the compare can be used by the Waveform Generator to generate a PWM or variable
frequency output on the Output Compare pin (OC1A/B).
A setting of 12 = 12 ticks of 0.5uS each = 6uS per toggle (Low->High or High->Low).
*/
}
// the loop function runs over and over again forever
void loop() {
// wait for a second
}
What I am getting:
About a 1Hz cycle that is not changing no matter the value for the OCR1A "compare" value is set to.
Sorted thanks!
Maybe not the way to do it...but just ended up with this:
#include <DHT.h>
#define DHTTYPE DHT22 // DHT 22 (AM2302), AM2321
DHT dht(2, DHTTYPE);
/*
TOP
The counter reaches the TOP when it becomes equal to the highest value in the count
sequence. The TOP value can be assigned to be one of the fixed values: 0x00FF, 0x01FF,
or 0x03FF, or to the value stored in the OCR1A or ICR1 Register. The assignment is
dependent of the mode of operation.
*/
byte led2 = 7;
byte led1 = 6;
void setup() {
dht.begin();
pinMode(led1, OUTPUT);
pinMode(led2, OUTPUT);
CLKPR = 0;
// Clock Pre-scale Register = 0. Clock division factor = 1 ie. 16Mhz external crystal.
// Data sheet -> Table 6-17 "Clock Prescalar Select". Using NO PRESCALAING...i.e. at 16Mhz.
TCCR1A = 0b01000000;
/*
Timer/Counter1 Control Register A
Bit 7 6 5 4 3 2 1 0
Format: COM1A1:COM1A0:COM1B1:COM1B0:---:---:WGM11:WGM10
Setting: 0 1 0 0 0 0 0 0
Note: Some WGM bits are in this register (TCCR1A) and 13 and 12
are in registr B (TCCR1B).
WGMbits 13:12:11:10 as 0:1:0:0 (mode 4) is:
"Mode = CTC, TOP = OCR1A, update = immediate, TOV1 flag set on MAX"
In CTC mode the counter is cleared to zero when the counter value
matches the OCR1A value.
The OCR1A or ICR1 define the top value for the counter
*/
TCCR1B = 0b00001001;
/*
// Timer/Counter1 Control Register B
// bit 7 6 5 4 3 2 1 0
// Format: ICNC1:ICES1:-:WGM13:WGM12:CS12:CS11:CS10
//Setting: 0 0 0 0 1 0 1 0
CS12:10 as 010 gives the 16Mhz clock as resilution of the counter.
WGM12 as 1 gives the CTC mode (mode 4).
*/
DDRB = 0
| (1 << PB1); //Set PB1 as OUTPUT (Pin 15 on IC / "OC1A"/ IDE 9 /PWM)
OCR1A = 210; // Counter Max...clock cycles before pin is toggled.
/* Output Compare Registers (OCR1A)
16Mhz = 1 clock increment per 6.2e-8 seconds.
Wanted 38Khz...so need (1/38e3)/2 seconds each toggle time (for period of 38KHz)
f = 1/38e3 / 2 = 0.00001315789 seconds
clk = 1/16e6 = 6.25e-8 seconds
ticks = f / clk = 210.526 ticks of the clock.
*/
}
// the loop function runs over and over again forever
void loop() {
float t = dht.readTemperature();
byte x = t;
flash(x);
delay(3000);
}
void flash(byte x) {
for (byte i = 0; i < x/10; i++) {
digitalWrite(led1, 1);
delay(500);
digitalWrite(led1, 0);
delay(200);
}
for (byte i = 0; i < x%10; i++) {
digitalWrite(led2, 1);
delay(200);
digitalWrite(led2, 0);
delay(200);
}
}
Incorrect. Johnny is using the expressions to create one fixed constant with every bit in the register set to the value it needs to be, then assigning it. There's nothing wrong with his method.
It only works because he has set TCCR1A to 0 and cleared all the bits.
The |= (0<< TargetBit) syntax is wrong for clearing a bit and I have seen people on this forum use it when a register has preexisting values in it. They write in and ask why what they have done doesn't work.
It more better to use the &= ~(1<< TargetBit) and become familiar with the syntax.
cattledog:
It only works because he has set TCCR1A to 0 and cleared all the bits.
The |= (0<< TargetBit) syntax is wrong for clearing a bit and I have seen people on this forum use it when a register has preexisting values in it. They write in and ask why what they have done doesn't work.
It more better to use the &= ~(1<< TargetBit) and become familiar with the syntax.
There is not a single |= operator in his entire sketch.
6v6gt:
So do you stand by the statement in your first post ?:
Or are you pointing out another error in the original post ?
I was pointing out an error in cattledog's post. There is no compound assignment (|=) being performed at all. If you remove all the comments and newlines, this is what Johnny is doing:
This is setting the entire register with the constant calculated from the bit values given. Every bit in the register is overwritten to the desired value.