Posted on Leave a comment

Inductor

Inductors are electronic components that store energy in the form of a magnetic field. They are used in a wide range of applications, from simple circuits to power supplies and filters. Understanding the principles of inductors is essential for designing and analyzing electronic circuits.

Inductance is the property of an inductor that opposes any change in the current flowing through it. The unit of inductance is the henry (H). The inductance of an inductor depends on the number of turns in the coil, the shape and size of the core, and the material of the core. The formula for calculating the inductance of an inductor is:

L = (μ * N^2 * A) / l

where L is the inductance in henries, μ is the magnetic permeability of the core material, N is the number of turns in the coil, A is the cross-sectional area of the core, and l is the length of the core.

Another important parameter of an inductor is its reactance, which is the opposition of an inductor to a change in the flow of alternating current. The reactance of an inductor is proportional to its inductance and the frequency of the alternating current. The formula for calculating the reactance of an inductor is:

XL = 2πfL

where XL is the reactance in ohms, f is the frequency in hertz, and L is the inductance in henries.

In addition to storing energy, inductors can also be used to filter out unwanted frequencies in a circuit. A low-pass filter, for example, can be created by connecting an inductor in series with a resistor and a capacitor. The inductor blocks high frequencies while allowing low frequencies to pass through, while the capacitor blocks low frequencies and allows high frequencies to pass through.

To illustrate the concept of inductance, let’s consider the following example:

Suppose we have a coil with 100 turns, a core with a cross-sectional area of 0.01 m^2, and a length of 0.1 m. The core is made of iron, which has a magnetic permeability of 2000. Calculate the inductance of the coil.

Using the formula for inductance, we have:

L = (μ * N^2 * A) / l L = (2000 * 100^2 * 0.01) / 0.1 L = 2,000 H

Therefore, the inductance of the coil is 2,000 henries.

Induktoren sind elektronische Bauteile, die Energie in Form eines magnetischen Feldes speichern. Sie werden in einer Vielzahl von Anwendungen eingesetzt, von einfachen Schaltkreisen bis hin zu Stromversorgungen und Filtern. Das Verständnis der Prinzipien von Induktoren ist wesentlich für das Entwerfen und Analysieren von elektronischen Schaltungen.

Induktivität ist die Eigenschaft eines Induktors, die jeder Änderung des durch ihn fließenden Stroms entgegenwirkt. Die Einheit der Induktivität ist das Henry (H). Die Induktivität eines Induktors hängt von der Anzahl der Windungen in der Spule, der Form und Größe des Kerns sowie dem Material des Kerns ab. Die Formel zur Berechnung der Induktivität eines Induktors lautet:

L = (μ * N^2 * A) / l

wobei L die Induktivität in Henry, μ die magnetische Permeabilität des Kernmaterials, N die Anzahl der Windungen in der Spule, A die Querschnittsfläche des Kerns und l die Länge des Kerns ist.

Ein weiterer wichtiger Parameter eines Induktors ist seine Reaktanz, die dem Widerstand eines Induktors gegen eine Änderung des Wechselstromflusses entspricht. Die Reaktanz eines Induktors ist proportional zu seiner Induktivität und der Frequenz des Wechselstroms. Die Formel zur Berechnung der Reaktanz eines Induktors lautet:

XL = 2πfL

wobei XL die Reaktanz in Ohm, f die Frequenz in Hertz und L die Induktivität in Henry ist.

Neben der Speicherung von Energie können Induktoren auch zum Filtern unerwünschter Frequenzen in einem Schaltkreis verwendet werden. Ein Tiefpassfilter kann beispielsweise durch Anschließen eines Induktors in Serie mit einem Widerstand und einem Kondensator erstellt werden. Der Induktor blockiert hohe Frequenzen und lässt niedrige Frequenzen durch, während der Kondensator niedrige Frequenzen blockiert und hohe Frequenzen durchlässt.

Um das Konzept der Induktivität zu veranschaulichen, betrachten wir das folgende Beispiel:

Angenommen, wir haben eine Spule mit 100 Windungen, einen Kern mit einer Querschnittsfläche von 0,01 m^2 und einer Länge von 0,1 m. Der Kern besteht aus Eisen, das eine magnetische Permeabilität von 2000 hat. Berechnen Sie die Induktivität der Spule.

Mit der Formel für Induktivität haben wir:

L = (μ * N^2 * A) / l
L = (2000 * 100^2 * 0,01) / 0,1
L = 2.000 H

Daher beträgt die Induktivität der Spule 2.000 Henry.

Posted on Leave a comment

AVR Input Output Port Programming

In AVR microcontroller programming, input/output ports are used to interface with external devices such as sensors, switches, LEDs, motors, and other peripherals. Here’s an example of how to program AVR input/output ports using C language:

#include <avr/io.h>
#include <util/delay.h>

int main(void)
{
    // Set PORTB as output and PORTC as input
    DDRB = 0xFF;
    DDRC = 0x00;

    while(1)
    {
        // Read the value of PINC3
        if(PINC & (1 << PINC3))
        {
            // If PINC3 is high, turn on LED connected to PB0
            PORTB |= (1 << PB0);
        }
        else
        {
            // If PINC3 is low, turn off LED connected to PB0
            PORTB &= ~(1 << PB0);
        }
    }
}

In this example, we set PORTB as an output port by setting all of its pins to output mode. We set PORTC as an input port by setting all of its pins to input mode. Then, we use a while loop to continuously check the value of PINC3. If PINC3 is high, we turn on an LED connected to PB0 by setting the corresponding bit in PORTB to high. If PINC3 is low, we turn off the LED by setting the corresponding bit in PORTB to low.

Note that the & and | operators are used to manipulate individual bits in the port registers. The << operator is used to shift the binary value of 1 to the left by a certain number of bits to set a particular bit high or low. The ~ operator is used to invert the value of a bit. The util/delay.h library is used to create a delay between each loop iteration.

Posted on Leave a comment

TIP3055 NPN BJT

It is a power transistor capable of handling power dissipation up to 90W for a few microseconds(generally less than 300 microseconds). Also, it has a Vceo of 60 V and a collector current of 15A.

TIP3055 is a widely used NPN power transistor that can handle high power and high voltage applications. It has a maximum collector-emitter voltage of 60V and a maximum collector current of 15A, making it ideal for use in power supplies, audio amplifiers, and motor control circuits. TIP3055 is a versatile transistor that can be used in a variety of circuit designs due to its high current gain and fast switching speeds. Its popularity can be attributed to its low cost, high reliability, and ease of use. With its ability to handle high power and voltage, TIP3055 is a go-to component for any circuit designer looking for a reliable power transistor.

It comes in a TO-247 package.
This is handy as it can be mounted to a heat sink with a nut bolt.

Datasheet Links

ST – https://www.st.com/resource/en/datasheet/tip3055.pdf

Onsemi – https://www.onsemi.com/pdf/datasheet/tip3055-d.pdf

Do all the companies that manufacture TIP3055 have exactly the same pinouts?

The TIP3055 transistor has a standardized pinout, which means that all manufacturers of this transistor must follow the same pinout configuration. The pinout configuration for the TIP3055 transistor is as follows:

  • Pin 1: Base
  • Pin 2: Collector
  • Pin 3: Emitter

Therefore, no matter which company manufactures the TIP3055 transistor, the pinout configuration should always be the same, and you can expect the same pinout configuration for TIP3055 transistors from different manufacturers. However, it is always recommended to check the datasheet provided by the manufacturer to confirm the pinout configuration and other specifications before using the transistor in a circuit.

Posted on Leave a comment

BD139 Pinout

The BD139 is a general-purpose NPN bipolar junction transistor (BJT). It has three pins:

  1. Base (B)
  2. Collector (C)
  3. Emitter (E)

There are two companies that manufacture the transistor

  1. STMicroelectronics
  2. onsemi

The pinout diagram according to STMicroelectronics is as follows:

When looking at the center hole and keeping the metal side down the pins are arranged from right to left as:

  1. Base (B)
  2. Collector (C)
  3. Emitter (E)

It’s important to note that the metal tab is connected to the Collector pin.

The pinout diagram according to ON Semiconductor is as follows:

When looking at the flat side of the transistor with the pins facing down and the metal tab facing up, the pins are arranged from left to right as follows:

  1. Emitter (E)
  2. Collector (C)
  3. Base (B)

It’s important to note that the metal tab is connected to the Collector pin.

Posted on Leave a comment

MC34063 DC-DC Step-Down Voltage Regulator

MC34063 is an integrated circuit which has all the essential components to make a DC-DC switching voltage regulator.

There are other popular switching regulators in the market. And the mc34063 IC is not the very best. But this chip is cheap.

As you can see from the block diagram. This chip contains an AND gate, an SR latch, two transistors, A 1.25V reference voltage and an op-amp configured as a comparator.

You can just choose any value of the component and think they will work.

There are very basic calculations which you need to perform in sequential order. The calculations are given in the datasheet.

You need to calculate in this particular sequence only.

  1. ton/toff
  2. (ton + toff)
  3. toff
  4. ton
  5. CT
  6. Ipk(switch)
  7. Rsc
  8. L(min)
  9. Co

You can also take the help of an online calculator for mc34063

http://www.nomad.ee/micros/mc34063a/

or you can create a spreadsheet.

You must read the SLVA252B Application of the MC34063 Switching Regulator

By following you can create the cheapest switching power supply.

There are a few considerations with this integrated circuit.

There is a lot of switching noise. So you will need a bigger capacitor if you want to dampen those noise signals.

If you want to reduce the size of the inductor used. Then you will need to use a higher switching frequency.

You need to remember that the L(min) you have selected is for a particular base frequency. The maximum frequency will be set up according to the load connected to it. And the maximum frequency of the oscillator is 100KHz according to the datasheet.

Posted on Leave a comment

How to use AT24C32 EEPROM with ATmega328PB in Microchip Studio

AT24C32 is an i2c compatible serial EEPROM which can be programmed using a microcontroller.

The AT24C32 provides 32,768 bits of serial electrically erasable and programmable
read-only memory (EEPROM). The device’s cascadable feature allows up to 8 devices to share a common 2-
wire bus. The device is optimized for use in many industrial and commercial applications
where low power and low voltage operation are essential. The AT24C32/64 is
available in space-saving 8-pin JEDEC PDIP, 8-pin JEDEC SOIC, 8-pin EIAJ SOIC,
and 8-pin TSSOP (AT24C64) packages and is accessed via a 2-wire serial interface.
In addition, the entire family is available in 2.7V (2.7V to 5.5V) and 1.8V (1.8V to 5.5V)
versions.

/*
 * main.c
 *
 * Created: 8/24/2022 10:53:05 PM
 *  Author: abhay
 */ 
#define F_CPU 16000000
#include <xc.h>
#include "util/delay.h"
#include "uart.h"
#include <stdio.h>
#define FALSE 0
#define TRUE 1

void EEOpen();
uint8_t EEWriteByte(uint16_t,uint8_t);
uint8_t EEReadByte(uint16_t address);

int main(void)
{
	UART_Init();
	EEOpen();
	char buff[20];
	sprintf(buff,"Hello EEPROM TEST \nBy: \t ABHAY");
	UART_SendString(buff);
	//Fill whole eeprom 32KB (32768 bytes)
	//with number 7
	uint16_t address;
	char failed;
	failed = 0 ;
	for(address=0;address< (32768);address++)
	{
		sprintf(buff,"address =  %d \n",address);
		UART_SendString(buff);
		if(EEWriteByte(address,5)==0)
		{
			//Write Failed
			sprintf(buff,"write Failed %x \n",address);
			UART_SendString(buff);
			failed = 1;
			break;
		}
	}
	
	if(!failed)
	{
		//We have Done it !!!
		
		sprintf(buff,"Write Success !\n");
		UART_SendString(buff);
	}
    while(1)
    {
        //TODO:: Please write your application code 
		//Check if every location in EEPROM has
		//number 7 stored
		failed=0;
		for(address=0;address < 32768 ; address++)
		{
			if(EEReadByte(address)!=5)
			{
				//Failed !
			
				
				sprintf(buff,"Verify Failed %x \n",address);
				UART_SendString(buff);
				
				failed=1;
				break;
			}
		}

		if(!failed)
		{
			//We have Done it !!!
			
			sprintf(buff,"Write Success !\n");
			UART_SendString(buff);
		}
		
    }
}


void EEOpen()
{
	//Set up TWI Module
	TWBR0 = 5;
	TWSR0 &= (~((1<<TWPS1)|(1<<TWPS0)));

}

uint8_t EEWriteByte(uint16_t address,uint8_t data)
{
	do
	{
		//Put Start Condition on TWI Bus
		TWCR0=(1<<TWINT)|(1<<TWSTA)|(1<<TWEN);

		//Poll Till Done
		while(!(TWCR0 & (1<<TWINT)));

		//Check status
		if((TWSR0 & 0xF8) != 0x08)
			return FALSE;

		//Now write SLA+W
		//EEPROM @ 00h
		TWDR0=0b10100000;	

		//Initiate Transfer
		TWCR0=(1<<TWINT)|(1<<TWEN);

		//Poll Till Done
		while(!(TWCR0 & (1<<TWINT)));
	
	}while((TWSR0 & 0xF8) != 0x18);
		

	//Now write ADDRH
	TWDR0=(address>>8);

	//Initiate Transfer
	TWCR0=(1<<TWINT)|(1<<TWEN);

	//Poll Till Done
	while(!(TWCR0 & (1<<TWINT)));

	//Check status
	if((TWSR0 & 0xF8) != 0x28)
		return FALSE;

	//Now write ADDRL
	TWDR0=(address);

	//Initiate Transfer
	TWCR0=(1<<TWINT)|(1<<TWEN);

	//Poll Till Done
	while(!(TWCR0 & (1<<TWINT)));

	//Check status
	if((TWSR0 & 0xF8) != 0x28)
		return FALSE;

	//Now write DATA
	TWDR0=(data);

	//Initiate Transfer
	TWCR0=(1<<TWINT)|(1<<TWEN);

	//Poll Till Done
	while(!(TWCR0 & (1<<TWINT)));

	//Check status
	if((TWSR0 & 0xF8) != 0x28)
		return FALSE;

	//Put Stop Condition on bus
	TWCR0=(1<<TWINT)|(1<<TWEN)|(1<<TWSTO);
	
	//Wait for STOP to finish
	while(TWCR0 & (1<<TWSTO));

	//Wait untill Writing is complete
	_delay_ms(1);

	//Return TRUE
	return TRUE;

}

uint8_t EEReadByte(uint16_t address)
{
	uint8_t data;

	//Initiate a Dummy Write Sequence to start Random Read
	do
	{
		//Put Start Condition on TWI Bus
		TWCR0=(1<<TWINT)|(1<<TWSTA)|(1<<TWEN);

		//Poll Till Done
		while(!(TWCR0 & (1<<TWINT)));

		//Check status
		if((TWSR0 & 0xF8) != 0x08)
			return FALSE;

		//Now write SLA+W
		//EEPROM @ 00h
		TWDR0=0b10100000;	

		//Initiate Transfer
		TWCR0=(1<<TWINT)|(1<<TWEN);

		//Poll Till Done
		while(!(TWCR0 & (1<<TWINT)));
	
	}while((TWSR0 & 0xF8) != 0x18);
		

	//Now write ADDRH
	TWDR0=(address>>8);

	//Initiate Transfer
	TWCR0=(1<<TWINT)|(1<<TWEN);

	//Poll Till Done
	while(!(TWCR0 & (1<<TWINT)));

	//Check status
	if((TWSR0 & 0xF8) != 0x28)
		return FALSE;

	//Now write ADDRL
	TWDR0=(address);

	//Initiate Transfer
	TWCR0=(1<<TWINT)|(1<<TWEN);

	//Poll Till Done
	while(!(TWCR0 & (1<<TWINT)));

	//Check status
	if((TWSR0 & 0xF8) != 0x28)
		return FALSE;

	//*************************DUMMY WRITE SEQUENCE END **********************


	
	//Put Start Condition on TWI Bus
	TWCR0=(1<<TWINT)|(1<<TWSTA)|(1<<TWEN);

	//Poll Till Done
	while(!(TWCR0 & (1<<TWINT)));

	//Check status
	if((TWSR0 & 0xF8) != 0x10)
		return FALSE;

	//Now write SLA+R
	//EEPROM @ 00h
	TWDR0=0b10100001;	

	//Initiate Transfer
	TWCR0=(1<<TWINT)|(1<<TWEN);

	//Poll Till Done
	while(!(TWCR0 & (1<<TWINT)));

	//Check status
	if((TWSR0 & 0xF8) != 0x40)
		return FALSE;

	//Now enable Reception of data by clearing TWINT
	TWCR0=(1<<TWINT)|(1<<TWEN);

	//Wait till done
	while(!(TWCR0 & (1<<TWINT)));

	//Check status
	if((TWSR0 & 0xF8) != 0x58)
		return FALSE;

	//Read the data
	data=TWDR0;

	//Put Stop Condition on bus
	TWCR0=(1<<TWINT)|(1<<TWEN)|(1<<TWSTO);
	
	//Wait for STOP to finish
	while(TWCR0 & (1<<TWSTO));

	//Return TRUE
	return data;
}

Posted on Leave a comment

How to use DS1307 RTC with ATmega328PB via I2C in Microchip Studio

The DS1307 Real Time Clock uses I2c communication lines to connect with the microcontroller.

I2C uses two lines commonly known as Serial Data/Address or SDA and Serial Clock Line or SCL. The two lines SDA and SCL are standardised and they are implemented using either an open collector or open drain configuration. What this means is that you need to pull these lines UP to VCC. For complete information on how the i2C is implemented in ATmega328PB, you need to go through the section of the datasheet called TWI or Two-Wire Serial Interface.

To start I2C in ATmega328PB, first the SCL frequency needs to set which must be under 100KHz .

To set the SCL frequency you set two registers TWBR0 and TWSR0.

TWSR0 has two bit 0 and bit 1; which sets the prescaler for the clock to the TWI.

Then TWBR0 needs to be set which can anything from 0 to 255.

THen you need to write the I2C functions for start, repeated start, data trasmission and recepetion and stop.

/*
 * main.c
 *
 * Created: 8/20/2022 2:08:09 PM
 *  Author: abhay
 */ 
#define F_CPU 16000000
#include <xc.h>
#include <avr/interrupt.h>

#include <stdio.h>
#include "util/delay.h"
#include "uart.h"


#define Device_Write_address	0xD0				/* Define RTC DS1307 slave address for write operation */
#define Device_Read_address		0xD1				/* Make LSB bit high of slave address for read operation */
#define TimeFormat12			0x40				/* Define 12 hour format */
#define AMPM					0x20

int second,minute,hour,day,date,month,year;

void TWI_init_master(void) // Function to initialize master
{
	TWBR0=127;    // Bit rate
	TWSR0= (1<<TWPS1)|(1<<TWPS0);    // Setting prescalar bits
	// SCL freq= F_CPU/(16+2(TWBR).4^TWPS)
}


								
uint8_t  I2C_Start(char write_address);			/* I2C start function */
uint8_t  I2C_Repeated_Start(char read_address);	/* I2C repeated start function */
void I2C_Stop();								/* I2C stop function */
void I2C_Start_Wait(char write_address);		/* I2C start wait function */
uint8_t  I2C_Write(char data);					/* I2C write function */
int I2C_Read_Ack();							/* I2C read ack function */
int I2C_Read_Nack();							/* I2C read nack function */

void RTC_Read_Clock(char read_clock_address)
{
	I2C_Start(Device_Write_address);				/* Start I2C communication with RTC */
	I2C_Write(read_clock_address);					/* Write address to read */
	I2C_Repeated_Start(Device_Read_address);		/* Repeated start with device read address */

	second = I2C_Read_Ack();						/* Read second */
	minute = I2C_Read_Ack();						/* Read minute */
	hour = I2C_Read_Nack();							/* Read hour with Nack */
	I2C_Stop();										/* Stop i2C communication */
}

void RTC_Read_Calendar(char read_calendar_address)
{
	I2C_Start(Device_Write_address);
	I2C_Write(read_calendar_address);
	I2C_Repeated_Start(Device_Read_address);

	day = I2C_Read_Ack();							/* Read day */
	date = I2C_Read_Ack();							/* Read date */
	month = I2C_Read_Ack();							/* Read month */
	year = I2C_Read_Nack();							/* Read the year with Nack */
	I2C_Stop();										/* Stop i2C communication */
}

int main(void)
{
	char buffer[20];
	const char* days[7]= {"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
	UART_Init();
	TWI_init_master();
	sei();
	
	I2C_Start(Device_Write_address);				/* Start I2C communication with RTC */
	I2C_Write(0);					/* Write address to read */
	I2C_Write(0x00);	//sec
	I2C_Write(0x00);	//min			/* Write address to read */
	I2C_Write(0x17);	//hour
	I2C_Write(0x03);	//tuesday
	I2C_Write(0x23);	//day
	I2C_Write(0x09);	//month
	I2C_Write(0x21);	//year
	I2C_Stop();										/* Stop i2C communication */
	

 

    
	while(1)
    {
        //TODO:: Please write your application code 
		RTC_Read_Clock(0);
		//UART_Transmit(second);
		sprintf(buffer, "\n%02x:%02x:%02x  ", (hour & 0b00011111), minute, second);
		UART_SendString(buffer);
		RTC_Read_Calendar(3);
		sprintf(buffer, "%02x/%02x/%02x %s", date, month, year,days[day-1]);
		UART_SendString(buffer);
		_delay_ms(1000);
    }
}

uint8_t I2C_Start(char write_address)						/* I2C start function */
{
	uint8_t status;											/* Declare variable */
	TWCR0 = (1<<TWSTA)|(1<<TWEN)|(1<<TWINT);					/* Enable TWI, generate start condition and clear interrupt flag */
	while (!(TWCR0 & (1<<TWINT)));							/* Wait until TWI finish its current job (start condition) */
	status = TWSR0 & 0xF8;									/* Read TWI status register with masking lower three bits */
	if (status != 0x08)										/* Check weather start condition transmitted successfully or not? */
	return 0;												/* If not then return 0 to indicate start condition fail */
	TWDR0 = write_address;									/* If yes then write SLA+W in TWI data register */
	TWCR0 = (1<<TWEN)|(1<<TWINT);							/* Enable TWI and clear interrupt flag */
	while (!(TWCR0 & (1<<TWINT)));							/* Wait until TWI finish its current job (Write operation) */
	status = TWSR0 & 0xF8;									/* Read TWI status register with masking lower three bits */
	if (status == 0x18)										/* Check weather SLA+W transmitted & ack received or not? */
	return 1;												/* If yes then return 1 to indicate ack received i.e. ready to accept data byte */
	if (status == 0x20)										/* Check weather SLA+W transmitted & nack received or not? */
	return 2;												/* If yes then return 2 to indicate nack received i.e. device is busy */
	else
	return 3;												/* Else return 3 to indicate SLA+W failed */
}

uint8_t I2C_Repeated_Start(char read_address)				/* I2C repeated start function */
{
	uint8_t status;											/* Declare variable */
	TWCR0 = (1<<TWSTA)|(1<<TWEN)|(1<<TWINT);					/* Enable TWI, generate start condition and clear interrupt flag */
	while (!(TWCR0 & (1<<TWINT)));							/* Wait until TWI finish its current job (start condition) */
	status = TWSR0 & 0xF8;									/* Read TWI status register with masking lower three bits */
	if (status != 0x10)										/* Check weather repeated start condition transmitted successfully or not? */
	return 0;												/* If no then return 0 to indicate repeated start condition fail */
	TWDR0 = read_address;									/* If yes then write SLA+R in TWI data register */
	TWCR0 = (1<<TWEN)|(1<<TWINT);							/* Enable TWI and clear interrupt flag */
	while (!(TWCR0 & (1<<TWINT)));							/* Wait until TWI finish its current job (Write operation) */
	status = TWSR0 & 0xF8;									/* Read TWI status register with masking lower three bits */
	if (status == 0x40)										/* Check weather SLA+R transmitted & ack received or not? */
	return 1;												/* If yes then return 1 to indicate ack received */
	if (status == 0x20)										/* Check weather SLA+R transmitted & nack received or not? */
	return 2;												/* If yes then return 2 to indicate nack received i.e. device is busy */
	else
	return 3;												/* Else return 3 to indicate SLA+W failed */
}

void I2C_Stop()												/* I2C stop function */
{
	TWCR0=(1<<TWSTO)|(1<<TWINT)|(1<<TWEN);					/* Enable TWI, generate stop condition and clear interrupt flag */
	while(TWCR0 & (1<<TWSTO));								/* Wait until stop condition execution */
}

void I2C_Start_Wait(char write_address)						/* I2C start wait function */
{
	uint8_t status;											/* Declare variable */
	while (1)
	{
		TWCR0 = (1<<TWSTA)|(1<<TWEN)|(1<<TWINT);				/* Enable TWI, generate start condition and clear interrupt flag */
		while (!(TWCR0 & (1<<TWINT)));						/* Wait until TWI finish its current job (start condition) */
		status = TWSR0 & 0xF8;								/* Read TWI status register with masking lower three bits */
		if (status != 0x08)									/* Check weather start condition transmitted successfully or not? */
		continue;											/* If no then continue with start loop again */
		TWDR0 = write_address;								/* If yes then write SLA+W in TWI data register */
		TWCR0 = (1<<TWEN)|(1<<TWINT);						/* Enable TWI and clear interrupt flag */
		while (!(TWCR0 & (1<<TWINT)));						/* Wait until TWI finish its current job (Write operation) */
		status = TWSR0 & 0xF8;								/* Read TWI status register with masking lower three bits */
		if (status != 0x18 )								/* Check weather SLA+W transmitted & ack received or not? */
		{
			I2C_Stop();										/* If not then generate stop condition */
			continue;										/* continue with start loop again */
		}
		break;												/* If yes then break loop */
	}
}

uint8_t I2C_Write(char data)								/* I2C write function */
{
	uint8_t status;											/* Declare variable */
	TWDR0 = data;											/* Copy data in TWI data register */
	TWCR0 = (1<<TWEN)|(1<<TWINT);							/* Enable TWI and clear interrupt flag */
	while (!(TWCR0 & (1<<TWINT)));							/* Wait until TWI finish its current job (Write operation) */
	status = TWSR0 & 0xF8;									/* Read TWI status register with masking lower three bits */
	if (status == 0x28)										/* Check weather data transmitted & ack received or not? */
	return 0;												/* If yes then return 0 to indicate ack received */
	if (status == 0x30)										/* Check weather data transmitted & nack received or not? */
	return 1;												/* If yes then return 1 to indicate nack received */
	else
	return 2;												/* Else return 2 to indicate data transmission failed */
}

int I2C_Read_Ack()											/* I2C read ack function */
{
	TWCR0=(1<<TWEN)|(1<<TWINT)|(1<<TWEA);					/* Enable TWI, generation of ack and clear interrupt flag */
	while (!(TWCR0 & (1<<TWINT)));							/* Wait until TWI finish its current job (read operation) */
	return TWDR0;											/* Return received data */
}

int I2C_Read_Nack()										/* I2C read nack function */
{
	TWCR0=(1<<TWEN)|(1<<TWINT);								/* Enable TWI and clear interrupt flag */
	while (!(TWCR0 & (1<<TWINT)));							/* Wait until TWI finish its current job (read operation) */
	return TWDR0;											/* Return received data */
}
Posted on Leave a comment

How to use UART Receive complete ISR of ATmega328PB using microchip studio

When you enable the communication using the UART. You have the flexibility to either use the Polling or Interrupt method to continue with your programming.

Polling halts the execution of the program and waits for the UART peripheral to receive something so that program execution must continue. But it eats a lot of the computing time.

So, Interrupt Service Routine is written and implemented such the program execution does not stop. It will stop when there is an interrupt and when there is data in the UDR0 register of UART. Then the ISR will execute and then transfer the control to the main program. Which saves a lot of computing time.

you have to add an interrupt library in your program.

#include <avr/interrupt.h>

Then you need to enable the Global interrupt flag.

.
.
.
int main()
{
.
.
.
sei();            // This is Set Enable Interryupt

   while(1)
  {
     // This is your application code.
   }

}

Then you need to enable the UART receive complete interrupt. by setting ‘1’ to RXCIE0 bit of USCR0B register.

Write the ISR function which takes “USART0_RX_vect” as the argument.

char Received_char;
ISR(USART0_RX_vect)
{
	Received_char = UDR0;
}

int main()
{
UCSR0B = (1 << RXCIE0)|(1<<RXEN0)|(1<<TXEN0); 
.
.
.
sei();
while(1);
{
}

}

The above code shows you how to implement UART receive complete ISR. It is not a full initialisation code. You still have to write the UBRR and the frame control to enable the uart peripheral.

Posted on Leave a comment

How to use internal temperature sensor of ATmega328pb

ATmega328PB is a new semiconductor microcontroller from Microchip semiconductors. I have used its previous generation which is ATmega328 and ATmega328P. They were usually found on Arduino Uno and Arduino nano.

This new IC has a temperature sensor built into it. Which is handy for measuring the die temperature. Which can make device stable in high-temperature design. It is not accurate as a dedicated temperature sensor. But it gives you a rough idea. Using this you can the processes.

It is not an Ambient temperature Sensor.

/*
 * main.c
 *
 * Created: 8/15/2022 4:06:41 PM
 *  Author: abhay
 */ 
#define F_CPU 16*1000000
#include <xc.h>
#include "uart.h"
#include "util/delay.h"
#include <stdlib.h>
long Ctemp;
unsigned int Ftemp;

int main(void)
{
		DDRD &= ~(1 << DDD0);							// PD0 - Rx Input
		DDRD |= (1 << DDD1);							// PD1 - Tx Ouput
		USART_Init();
		
	/* Replace with your application code */
	ADMUX = (1<<REFS1) | (1<<REFS0) | (0<<ADLAR) | (1<<MUX3) | (0<<MUX2) | (0<<MUX1) | (0<<MUX0);
	ADCSRA =  (1<<ADPS2) |(1<<ADPS1) | (1<<ADEN);
	
	ADCSRA |= (1<<ADSC);
	
	while ((ADCSRA & (1<<ADSC)) !=0);
	
	while (1)
	{
		ADCSRA |= (1<<ADSC);
		while ((ADCSRA & (1<<ADSC)) !=0);
		
		Ctemp = ((ADC - 247)/1.22)*1000;
		Ftemp = (Ctemp * 1.8) + 32;
		
		USART_Transmit( (((int)Ctemp/100000)%10) + 48);
		USART_Transmit( (((int)Ctemp/10000)%10) + 48);
		USART_Transmit( (((int)Ctemp/1000)%10) + 48);
		USART_Transmit('.');
		USART_Transmit( (((int)Ctemp/100)%10) + 48);
		USART_Transmit( (((int)Ctemp/10)%10) + 48);
		USART_Transmit( ((int)Ctemp%10) + 48);
		
		USART_Transmit('\n');
		_delay_ms(1000);
	}
	return -1;
}
Posted on Leave a comment

How to add USBASP as External Tool in Microchip studio

Download microchip studio from here https://www.microchip.com/en-us/tools-resources/develop/microchip-studi

Install the program.

I use USBASP to program AVR ATmega328pb.

Go to Tools > External Tools > ADD

Command: location of avrdude

C:\WinAVR-20100110\bin\avrdude.exe

Arguments:

-c usbasp -p m328pb -U flash:w:$(ProjectDir)Debug\$(TargetName).hex:i

Check the Use Output window to be able to see the output of the avrdude inside the microchip studio terminal.