/* * PWM-LF.c * * Created: 29.01.2017 23:43:39 * Author : Petter */ #define F_CPU 3333333UL #include #include #include #include #define LED1 0 // port B, connected to WO0 #define LED2 1 // port B, connected to WO1 #define LED3 4 // Port B #define SW1 5 // Port A #define SW2 6 // Port A #define SW3 7 // Port A bool SW1_pressed,SW2_pressed; //Keeping track of button status int main(void) { //Set LED pins as output PORTB.DIRSET = (1 << LED1) | (1 << LED2) | (1 << LED3); //Because the LEDs are active low, we invert the output. This means high PWM value -> bright led PORTB.PIN0CTRL |= (1 << PORT_INVEN_bp); PORTB.PIN1CTRL |= (1 << PORT_INVEN_bp); PORTB.PIN4CTRL |= (1 << PORT_INVEN_bp); //Pullups PORTA.PIN5CTRL |= (1 << PORT_PULLUPEN_bp); PORTA.PIN6CTRL |= (1 << PORT_PULLUPEN_bp); PORTA.PIN7CTRL |= (1 << PORT_PULLUPEN_bp); /*We will be using timer 1 in single (not split) mode. It is highly recommended that you read chapter 20.3.3.4 in the datasheet on timer compare channels. There you will find a sub-capter on the single-slope PWM we will be using. */ //First, enable the timer TCA0.SINGLE.CTRLA |= (TCA_SINGLE_ENABLE_bm); //Set the mode of the timer to single slope PWM TCA0.SINGLE.CTRLB |= (0x03 << TCA_SINGLE_WGMODE0_bp); //We have to override the normal pin opperation so the PWM is pushed directly to the pin //Hint: WO0 and WO1 are connected to leds. We need to override them to get the PWM out. TCA0.SINGLE.CTRLB |= (TCA_SINGLE_CMP0EN_bm) | (TCA_SINGLE_CMP1EN_bm); /*Timer A is a 16 bit timer. This will give us a frequency of 25Hz, we can see it flicker. By lowering the period, (PER) we get higher frequency at the cost of lower resolution. */ //Set the period to 12 bit. (This results in a frequency of ~400Hz.) TCA0.SINGLE.PER = 0x0fff; //We set our top to have a sufficiently high frequency (Top at 16 bit (0xffff) ~25Hz, 12 bit (0x0fff) ~400Hz) //We can now control the PWM duty cycle by simply writing values to the CMP0 and CMP1 registers. TCA0.SINGLE.CMP0 = 0x0000; //We have inverted the pin outputs so this is MIN TCA0.SINGLE.CMP1 = 0x0fff; //We have inverted the pin outputs so this is MAX while(1){ /*Have some fun with the leds. Examples: Have them fade between max and min Have them fade in a pattern (Heartbeat?) Change the brightness based on buttons */ //Here we use button pushes to shift the CMP register so we get brightness steps //adding and subtracting works just as well //It is largely up to the student to choose how the led brightness is changed. if (!(PORTA.IN & (1 << SW1))){ if(!SW1_pressed){ TCA0.SINGLE.CMP0 = (((TCA0.SINGLE.CMP0 << 1) + 1) & (0x0fff)); //Shift in a 1, and cut off excess to 12 bit TCA0.SINGLE.CMP1 >>= 1; SW1_pressed = true; } } else{ SW1_pressed = false; } if (!(PORTA_IN & (1 << SW2))){ if(!SW2_pressed){ TCA0.SINGLE.CMP1 = (((TCA0.SINGLE.CMP1 << 1) + 1) & (0x0fff)); //Shift in a 1, and cut off excess to 12 bit TCA0.SINGLE.CMP0 >>= 1; SW2_pressed = true; } } else{ SW2_pressed = false; } } }