Arduino operates on an 8-bit architecture for its registers and ports. Each register consists of 8 bits, as shown below:
| MSB | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | LSB |
|---|
- Configure pins as either input or output:
0-> Input1-> Output
- Set the output value (HIGH/LOW) for the pins configured as output.
- Read the value of the input pins.
- AND operation:
& - OR operation:
|
| DDB7 | DDB6 | DDB5 | DDB4 | DDB3 | DDB2 | DDB1 | DDB0 |
|---|
The DDRB register configures whether the pins in port B are inputs or outputs.
- Code:
or can be written as
DDRB = DDRB | (1 << DDB0);
DDRB |= (1 << DDB0);
- Explanation:
-
Initial DDRB:
0 0 0 0 0 0 0 0 -
Apply
(1 << DDB0):0 0 0 0 0 0 0 1 -
Resulting DDRB:
0 0 0 0 0 0 0 1
-
- Code:
DDRB |= (1 << DDB0) | (1 << DDB1);
- Code:
or can be written as
DDRB = DDRB & ~(1 << DDB0);
DDRB &= ~(1 << DDB0);
- Explanation:
-
Initial DDRB:
0 0 0 0 0 0 1 1 -
Apply
~(1 << DDB0):1 1 1 1 1 1 1 0 -
Resulting DDRB:
0 0 0 0 0 0 1 0
-
- Code:
or can be written as
DDRB = 0x00001111;
DDRB = 0x0F;
- Code:
or can be written as
DDRB = 0x01100001;
DDRB = 0x61;
| PB7 | PB6 | PB5 | PB4 | PB3 | PB2 | PB1 | PB0 |
|---|
| X | PC6 | PC5 | PC4 | PC3 | PC2 | PC1 | PC0 |
|---|
| PD7 | PD6 | PD5 | PD4 | PD3 | PD2 | PD1 | PD0 |
|---|
0-> LOW1-> HIGH
- Code:
or
PORTB |= (1 << PB5);
orPORTB = 0x00100000;
PORTB = 0x20;
| PINB7 | PINB6 | PINB5 | PINB4 | PINB3 | PINB2 | PINB1 | PINB0 |
|---|
| X | PINC6 | PINC5 | PINC4 | PINC3 | PINC2 | PINC1 | PINC0 |
|---|
| PIND7 | PIND6 | PIND5 | PIND4 | PIND3 | PIND2 | PIND1 | PIND0 |
|---|
- Code:
if (PINB & (1 << PINB0)) { // Pin PB0 is HIGH } else { // Pin PB0 is LOW }
- Explanation:
-
If
PINB & (1 << PINB0)evaluates to:0-> Pin is LOW.1-> Pin is HIGH.
-
Case 1: LOW value in pin B
- PINB
0 0 0 0 0 0 0 0 - (1 << PINB0)
0 0 0 0 0 0 0 1 - PINB & (1 << PINB0)
0 0 0 0 0 0 0 0 -
Case 2: HIGH value in pin B
- PINB
0 0 0 0 0 0 0 1 - (1 << PINB0)
0 0 0 0 0 0 0 1 - PINB & (1 << PINB0)
0 0 0 0 0 0 0 1
-
-
Hardware Interrupts
- Triggered by external events.
- Example: External interrupts on pins.
-
Software Interrupts
- Triggered by internal events.
- Example: ADC, Timer, or USART interrupts.
- Bit 7: I (Global Interrupt Enable bit)
- Code to enable:
SREG |= (1 << 7);
- Code to enable:
- Bit 1: INT1 - External Interrupt 1
- Bit 0: INT0 - External Interrupt 0
-
Bit 3: ISC11 - Interrupt Sense Control for INT1 (Bit 1)
-
Bit 2: ISC10 - Interrupt Sense Control for INT1 (Bit 0)
-
Bit 1: ISC01 - Interrupt Sense Control for INT0 (Bit 1)
-
Bit 0: ISC00 - Interrupt Sense Control for INT0 (Bit 0)
-
Rising edge interrupt request:
ISC11 = 1; ISC10 = 1; ISC01 = 1; ISC00 = 1;
- Generate delays or time intervals.
- Measure time or frequency.
- Generate PWM signals.
- Trigger external devices.
- The timer increments at each clock cycle.
- Timer clock can be reduced using a prescaler.
Timer Clock = System_Clock / PrescalerTimer Period = 1 / 16 MHz = 62.5 ns- TIMER 0: 8-bit
- TIMER 1: 16-bit
- TIMER 2: 8-bit
SREG |= (1 << 7); // sei();-
TCCR1A Register Overview: The TCCR1A register controls the behavior of Timer/Counter 1 in terms of output compare behavior and the PWM mode. This register is crucial for configuring how the microcontroller generates PWM signals and how it interacts with output pins.
-
PWM Configuration:
- PWM Mode (Waveform Generation Mode): The WGM11 and WGM10 bits in TCCR1A set the waveform generation mode, which determines how the timer operates. In PWM mode, Timer/Counter 1 generates a pulse-width modulation (PWM) signal on the output pin (OC1A or OC1B).
- COM1A and COM1B Bits: The COM1A1, COM1A0, COM1B1, and COM1B0 bits control the output compare behavior on pins OC1A and OC1B. These bits specify whether the output will be toggled, cleared, or set when the timer reaches a certain value. They help in controlling whether the waveform is inverted (active high or low) or non-inverted.
-
TCCR1A Register:
Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0 COM1A1 COM1A0 COM1B1 COM1B0 - - WGM11 WGM10
| COM1A1 | COM1A0 | Description |
|---|---|---|
| 0 | 0 | Normal port operation (OC1A disconnected) |
| 0 | 1 | Toggle OC1A on compare match |
| 1 | 0 | Clear OC1A on compare match (non-inverted) |
| 1 | 1 | Set OC1A on compare match (inverted) |
| COM1B1 | COM1B0 | Description |
|---|---|---|
| 0 | 0 | Normal port operation (OC1B disconnected) |
| 0 | 1 | Toggle OC1B on compare match |
| 1 | 0 | Clear OC1B on compare match (non-inverted) |
| 1 | 1 | Set OC1B on compare match (inverted) |
| WGM11 | WGM10 | Description |
|---|---|---|
| 1 | 1 | Fast PWM (with ICR1 as the TOP value) |
| 0 | 0 | Normal mode |
| 1 | 0 | CTC (Clear Timer on Compare Match) |
| 0 | 1 | Phase Correct PWM |
-
TCCR1B Register Overview: The TCCR1B register controls Timer/Counter 1's behavior in terms of clock selection, waveform generation modes, and prescaling. It is essential for setting the timer's frequency, mode of operation, and the output signal's characteristics.
-
PWM Configuration:
- WGM13, WGM12: These bits, in combination with WGM11 and WGM10 from TCCR1A, define the waveform generation mode for Timer/Counter 1. They determine whether the timer is operating in normal mode, CTC, PWM, or phase-correct PWM.
- CS1[2:0]: The CS1 bits define the clock source for the timer and the prescaling factor. These bits allow the user to select the clock frequency for the timer, which can be divided by a factor to slow down the timer and generate PWM signals with desired frequencies.
-
TCCR1B Register:
Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0 ICNC1 ICES1 WGM13 WGM12 CS12 CS11 CS10
| ICNC1 | Description |
|---|---|
| 0 | Disable the noise canceler |
| 1 | Enable the noise canceler |
| ICES1 | Description |
|---|---|
| 0 | Capture on falling edge |
| 1 | Capture on rising edge |
| WGM13 | WGM12 | Description |
|---|---|---|
| 1 | 1 | Fast PWM (with ICR1 as the TOP value) |
| 0 | 0 | Normal mode |
| 1 | 0 | CTC (Clear Timer on Compare Match) |
| 0 | 1 | Phase Correct PWM |
| CS12 | CS11 | CS10 | Description |
|---|---|---|---|
| 0 | 0 | 0 | No clock source (Timer/Counter stopped) |
| 0 | 0 | 1 | Clock with no prescaling |
| 0 | 1 | 0 | Clock divided by 8 |
| 0 | 1 | 1 | Clock divided by 64 |
| 1 | 0 | 0 | Clock divided by 256 |
| 1 | 0 | 1 | Clock divided by 1024 |
| 1 | 1 | 0 | External clock on T1 pin, falling edge |
| 1 | 1 | 1 | External clock on T1 pin, rising edge |
- Pulse Width Modulation (PWM) is used to control the average power delivered to a load by varying the duty cycle of a signal.
- It is widely used in various applications such as motor control, audio control, and lighting control, among others.
- Motor Control: Used to control the speed of motors by adjusting the average voltage applied.
- Audio Control: Used in audio systems to adjust sound levels or modulate audio signals.
- Lighting Control: Commonly used in LED dimming applications where light intensity is controlled by adjusting the duty cycle.
| Mode | WGM1[3] | WGM1[2] | WGM1[1] | WGM1[0] | Timer/Counter Mode of Operation | TOP |
|---|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | Normal | 0xFFFF |
| 1 | 0 | 0 | 0 | 1 | PWM, Phase Correct, 8-bit | 0x00FF |
| 2 | 0 | 0 | 1 | 0 | PWM, Phase Correct, 9-bit | 0x01FF |
| 3 | 0 | 0 | 1 | 1 | PWM, Phase Correct, 10-bit | 0x03FF |
| 4 | 0 | 1 | 0 | 0 | CTC | OCR1A |
| 5 | 0 | 1 | 0 | 1 | Fast PWM, 8-bit | 0x00FF |
| 6 | 0 | 1 | 1 | 0 | Fast PWM, 9-bit | 0x01FF |
| 7 | 0 | 1 | 1 | 1 | Fast PWM, 10-bit | 0x03FF |
| 8 | 1 | 0 | 0 | 0 | PWM, Phase and Frequency Correct | ICR1 |
| 9 | 1 | 0 | 0 | 1 | PWM, Phase and Frequency Correct | OCR1A |
| 10 | 1 | 0 | 1 | 0 | PWM, Phase Correct | ICR1 |
| 11 | 1 | 0 | 1 | 1 | PWM, Phase Correct | OCR1A |
| 12 | 1 | 1 | 0 | 0 | CTC | ICR1 |
| 13 | 1 | 1 | 0 | 1 | Reserved | - |
| 14 | 1 | 1 | 1 | 0 | Fast PWM | ICR1 |
| 15 | 1 | 1 | 1 | 1 | Fast PWM | OCR1A |
-
Normal Mode (WGM1[3:0] = 0000):
- The timer counts from 0 to 255, then resets to 0, allowing for simple counting.
- Typically used for simple timing and frequency generation.
-
Phase Correct PWM Mode (WGM1[3:0] = 0001, 0010, 0011):
- The timer counts up to a specified value and then counts back down.
- It generates a symmetrical waveform, where the duty cycle can be adjusted from 0 to 100%.
- Commonly used for motor control, smooth LED dimming, and audio applications.
-
CTC (Clear Timer on Compare Match) Mode (WGM1[3:0] = 0100, 1100):
- The timer counts to a specified value (OCR1A or ICR1) and resets to 0 on a match.
- Used for precise frequency generation, event timing, and generating periodic interrupts.
-
Fast PWM Mode:
- The timer counts to a specified value (ICR1 or OCR1A) and resets to 0.
- Offers high-frequency PWM with resolutions of 8, 9, or 10 bits.
- Ideal for applications requiring high-speed control of motors, LEDs, and other power-sensitive devices, with very fine control over the duty cycle.
The Analog-to-Digital Converter (ADC) converts an analog signal (like the output from a sensor) into a digital value that the microcontroller can understand. This is important because most microcontrollers only work with digital data.
Here’s an overview of the key parts of the ADC:
- ADC Multiplexer: This selects which analog input to convert. It allows the ADC to work with multiple inputs (like ADC0, ADC1, etc.).
- Sample & Hold Circuit: This captures the analog voltage at a specific time so it can be converted.
- Comparator: Compares the analog signal to a reference voltage to determine how the signal measures.
- Conversion Logic: Converts the comparison result into a digital number.
- Data Registers: The converted digital value is stored in these registers.
- Select the Input Channel: Choose the sensor input you want to measure by setting the appropriate control bits.
- Choose Reference Voltage: Set the reference voltage (internal or external).
- Enable the ADC: Turn on the ADC by setting the necessary control bit.
- Start the Conversion: Begin the process by triggering the conversion.
- Sample the Input: The ADC takes a snapshot of the analog input voltage.
- Compare the Voltage: The ADC compares the input to a series of reference voltages using a Successive Approximation Register (SAR).
- Convert to Digital: The ADC converts the result of the comparison into a 10-bit digital number.
- Store the Result: The result is stored in two memory registers: ADCL (lower 8 bits) and ADCH (higher 8 bits).
- Reference Voltage: This is the voltage that the ADC compares the input signal to. It can be set to an internal or external reference.
- Left Adjustment: You can adjust the result so that the most significant bits are stored in the higher register, which is useful for 8-bit precision.
- Power Consumption: The ADC uses power when it's on. It’s a good idea to turn it off when you’re not using it to save power.
The step size is an important concept in ADC conversion. It refers to the smallest difference between two distinct digital values that the ADC can detect. This depends on the reference voltage and the resolution of the ADC.
- Formula for Step Size:
[
\text{Step Size} = \frac{\text{Reference Voltage}}{2^{\text{Resolution of ADC}}-1}
]
Where:
- Reference Voltage is the voltage range (e.g., 0V to 5V).
- Resolution of ADC is the number of bits the ADC uses to represent the digital value.
For example, if you have a 10-bit ADC with a reference voltage of 5V: [ \text{Step Size} = \frac{5V}{2^{10}} = \frac{5V}{1024} \approx 0.00488V ] This means that the ADC can detect changes in the input voltage as small as 0.00488V.
-
ADMUX Register Overview: The ADMUX register controls the selection of the input channel, reference voltage, and the adjustment of the ADC result in the ATmega328P. It is crucial for configuring which analog pin to sample, selecting the reference voltage for conversion, and adjusting the format of the output result.
-
ADC Configuration:
- MUX[4:0]: These bits select the analog input channel for the ADC. The ATmega328P has 8 input channels (ADC0-ADC7), which can be configured using these bits.
- REFS[1:0]: These bits define the reference voltage used by the ADC. The reference voltage can either be external or come from an internal source such as Vcc or an internal 1.1V bandgap.
- ADLAR: This bit controls the left-adjustment of the ADC result. When set, the ADC result is left-adjusted, which is useful for applications where only 8-bit precision is needed.
-
ADMUX Register:
Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0 REFS1 REFS0 ADLAR MUX3 MUX2 MUX1 MUX0
| REFS[1:0] | Description |
|---|---|
| 00 | AREF, Internal Vref turned off |
| 01 | AVCC with external capacitor at AREF pin |
| 10 | Reserved, do not use |
| 11 | Internal 1.1V Voltage Reference with external capacitor |
When ADLAR is set to 0, the 10-bit ADC result is right-adjusted. In this case:
- The ADCL register stores the lower 8 bits (ADC0-ADC7).
- The ADCH register stores the upper 2 bits (ADC8-ADC9).
| Address | Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 |
|---|---|---|---|---|---|---|---|---|
| 0x79 | - | - | - | - | - | - | ADC9 | ADC8 |
| 0x78 | ADC7 | ADC6 | ADC5 | ADC4 | ADC3 | ADC2 | ADC1 | ADC0 |
- ADCL (0x78): Stores the lower 8 bits of the ADC result (ADC0-ADC7).
- ADCH (0x79): Stores the upper 2 bits of the ADC result (ADC8-ADC9).
In this mode, the complete 10-bit result is obtained by reading both ADCL and ADCH.
When ADLAR is set to 1, the 10-bit ADC result is left-adjusted. In this case:
- The ADCL register stores the upper 8 bits (ADC0-ADC7).
- The ADCH register stores the lower 2 bits (ADC8-ADC9), which can be ignored if only 8-bit precision is required.
| Address | Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 |
|---|---|---|---|---|---|---|---|---|
| 0x79 | ADC9 | ADC8 | ADC7 | ADC6 | ADC5 | ADC4 | ADC3 | ADC2 |
| 0x78 | ADC1 | ADC0 | - | - | - | - | - | - |
- ADCL (0x78): Stores the upper 8 bits of the ADC result (ADC0-ADC7).
- ADCH (0x79): Stores the lower 2 bits of the ADC result (ADC8-ADC9), which can be ignored in most cases if only 8-bit precision is needed.
In this mode, the 8-bit result is obtained directly by reading ADCL, and ADCH contains the lower bits (which can be ignored).
| MUX[3:0] | Input Channel |
|---|---|
| 0000 | ADC0 (Pin 23) |
| 0001 | ADC1 (Pin 24) |
| 0010 | ADC2 (Pin 25) |
| 0011 | ADC3 (Pin 26) |
| 0100 | ADC4 (Pin 27) |
| 0101 | ADC5 (Pin 28) |
| 0110 | ADC6 (Pin 29) |
| 0111 | ADC7 (Pin 30) |
| 1000 | Temperature sensor |
| 1001 | Reserved |
| 1010 | Reserved |
| 1011 | Reserved |
| 1100 | Reserved |
| 1101 | Reserved |
| 1110 | 1.1V (VBG) |
| 1111 | 0V (GND) |
-
ADCSRA Register Overview: The ADCSRA register controls the operation of the ADC (Analog-to-Digital Converter) in the ATmega328P. It is responsible for enabling the ADC, starting conversions, enabling interrupts, and setting the ADC prescaler to control the ADC conversion speed. This register is essential for configuring and managing ADC operations.
-
Key Configuration:
- ADEN (ADC Enable): This bit enables or disables the ADC. Setting it to 1 enables the ADC and allows conversions to be performed.
- ADSC (ADC Start Conversion): When this bit is set to 1, the ADC conversion process begins. This bit is automatically cleared once the conversion is complete.
- ADATE (ADC Auto Trigger Enable): This bit enables the auto-triggering of the ADC, allowing continuous conversions based on a trigger source.
- ADIF (ADC Interrupt Flag): This flag is set when an ADC conversion is complete and an interrupt is triggered. It is cleared by writing a 1 to it.
- ADIE (ADC Interrupt Enable): This bit enables or disables ADC conversion interrupts. Setting it to 1 enables interrupts.
- ADPS[2:0] (ADC Prescaler Selection): These bits select the division factor for the ADC clock. The prescaler is used to slow down the ADC clock to ensure proper operation.
-
ADCSRA Register:
Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0 ADEN ADSC ADATE ADIF ADIE ADPS2 ADPS1 ADPS0
| ADEN | Description |
|---|---|
| 0 | Disable ADC operation |
| 1 | Enable ADC operation |
| ADSC | Description |
|---|---|
| 0 | No conversion in progress |
| 1 | Start an ADC conversion |
| ADATE | Description |
|---|---|
| 0 | Auto triggering disabled |
| 1 | Enable auto triggering of ADC |
| ADIF | Description |
|---|---|
| 0 | ADC conversion is not complete |
| 1 | ADC conversion is complete |
| ADIE | Description |
|---|---|
| 0 | Disable ADC conversion interrupt |
| 1 | Enable ADC conversion interrupt |
| ADPS2 | ADPS1 | ADPS0 | Division Factor |
|---|---|---|---|
| 0 | 0 | 0 | 2 |
| 0 | 0 | 1 | 2 |
| 0 | 1 | 0 | 4 |
| 0 | 1 | 1 | 8 |
| 1 | 0 | 0 | 16 |
| 1 | 0 | 1 | 32 |
| 1 | 1 | 0 | 64 |
| 1 | 1 | 1 | 128 |
- Configure ADC:
- Enable the ADC.
- Set the reference voltage to AVCC.
- Select the ADC channel.
- Set the prescaler for ADC clock.
- Start ADC Conversion:
- Initiate the conversion.
- Wait for the conversion to complete.
- Read the digital value.
- Set Up Timer for PWM:
- Configure Timer1 for Fast PWM mode.
- Set the PWM frequency using ICR1.
- Enable the non-inverting mode for OC1A.
- Set the clock source for the timer.
- Output PWM Signal:
- Assign the scaled ADC value to the PWM duty cycle register.
- Ensure the corresponding PWM output pin is configured as output.
- Loop to Continuously Update:
- Read the ADC value.
- Scale it to 8-bit resolution.
- Update the PWM duty cycle.
- Add a small delay for stabilization.