I have a little project at the university where I have to use the timers to generate a pwm signal and get it into a piezo buzzer when something else turns over a certain value by using the registers, the thing is that we have worked on some other microcontrollers so I don't really know the libraries for arduino uno with atmega328p and I would require some help on that. Also I have to use the registers instead of the function analogRead() that is reading from a temperature sensor.

Having the following code that works for my setup:

#include <LiquidCrystal.h>         

LiquidCrystal lcd(12, 11, 5, 4, 3, 2); //Digital pins to which you connect the LCD
const int inPin = 0; 
const int buzzer=9;// A0 is the sensor
void setup()
  pinMode(buzzer,OUTPUT); // DDRA=0b00000001;
void loop()
  int value = analogRead(inPin); // read the value from the sensor <= to be written on registers
  float millivolts = (value / 1024.0) * 5; 
  float celsius = (millivolts-0.5)*100;
  lcd.print((celsius * 9)/5 + 32); //turning the celsius into fahrehait
  if(celsius>30.0){tone(buzzer,1000);delay(1000);noTone(buzzer);delay(1000);} //<= on registers
  • 1
    Step one: read the ATMega328P datasheet. That has all the information you need.
    – Majenko
    Dec 31, 2019 at 11:41
  • So is your question; how to convert the above code to use registers instead?
    – Gerben
    Dec 31, 2019 at 13:28

1 Answer 1


In fact all the mentioned function calls are using the Special Function Registers (SFR) and thus the hardware peripherals of the Arduino in the background to work. But I guess this is an exercise to learn how to configure and use these peripherals yourself. Doing this for the whole code is a rather big task for a single question on this site. So I will give you hints and will point you to the corresponding registers. Then the datasheet of the Atmega328P (the microcontroller on the Arduino Uno) is a must read for you. It contains detailed descriptions for almost every function and SFR of the microcontroller.

  1. PWM: I think you want to use PWM for creating a tone from your buzzer. This is not the classical PWM use case (as you don't need to change the duty cycle but the frequency to get different tones). Nonetheless you reach it with the same hardware. For hardware PWM you need to configure a Timer. The Uno has 3 Timers, where Timer0 is already configured by the Arduino IDE for functions like delay(), millis() and such. So I suggest you use Timer1. It has 3 control registers called TCCR1A to TCCR1C. You want the timer to be in CTC Mode (Clear Timer on Compare Match)(Waveform Generation Mode Bits set to 4, CTC mode for OCR1A). The timer will count up with the set frequency (will describe this later) until it gets to the value, that you wrote into the OCR1A register (Compare Match). Then it will reset. If you have set the COM1Ax bits in the TCCR1A register to the correct values, you can set it up to toggle the OC1A pin on a Compare Match).

    So in this mode, the timer will reset at a counter value that you set and will toggle the OC1A output pin for you. Thus it generates a square wave with variable frequency, that you can control by writing different values to the OCR1A register.

    But we also need to configure the frequency with which the timer will count up. This is done by the clock selection bits CS10 to CS12 in the TCCR1B register. A value of 0 for all bits means the timer is stopped. Look at the corresponding table in the Timer1 register descriptions in the datasheet. You want to connect the timer to the internal system clock. With these bits you can set the prescaler. This determines how many clock pulses it needs to let the timer count 1 up. With no prescaler the timer will count at every clock pulse. With the bit values 0 1 1 you will get a prescaler of 64, so the timer will count up 1 every 64 clock pulses. This sets the frequency range, that you have with the counter. The internal system clock runs at 16MHz on the Uno (you can do the math with the prescaler to calculate for the wanted frequency).

  2. analogRead aka ADC: For reading an analog voltage the ADC (Analog Digital Converter) is used. It has the SFRs ADMUX, ADCSRA, the convertion result registers ADCL and ADCH, and ADCSRB. First we want to set the reference voltage for our conversion. When we set the REFS1 and REFS0 bits in the ADMUX register to 01 we use Vcc as voltage reference, which is sufficient most of the time. The bits MUX3 to MUX0 in the same register select one of the ADC pins for AD Conversion (We have only 1 ADC in the Atmega328P, but we can connect it to multiple ADC pins one after another). Now on the ADCSRA register: The ADEN bit will enable the ADC, with ADSC we can start a conversion. With the bits ADPS2 to ADPS0 we can select a clock prescaler for the ADC. This determines how fast the ADC runs. For maximum resolution you should keep the frequency between 50 and 200kHz.

    You can start a conversion by writing 1 to the ADSC. Then you can poll the ADIF bit in the same register. It will be set to 1, when the ADC has completed the conversion. Then you can read the conversion result from the ADCL and ADCH registers (for the Low byte and the High byte of the 10bit result). You should reset the ADIF bit after that by writing a 1 to it.

  3. LCD: I don't know, if you also need to replace the LiquidCrystal library by your own code, since it does not use special peripherals (just digital pins). Digital pins are controlled via the DDRx, PORTx and PINx registers. Google "arduino port manipulation" for more information. And then you can resemble the functions from the library with it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.