Smallest (code-wise) bit - banged serial interface on PIC10 - pic

I need to interface to a PIC10 micro with some serial interface. Since these small devices lack hardware support for SPI I2C and UART a Software solution is inevitable.
However, since I need to preserve as much of the Programm memory to store (static) configuration and identify information to be retrieved via said interface, what would probably be the smallest solution?
I will need to program this in ASM since there seems no good C compiler for PIC10. However, this will be my first real encounter with ASM to speak of.

Try this download which contains code samples and says:
"Listed below are five PIC UART software routines to use with PIC microprocessors that have no hardware UART"
Link rot has broken the original link try this link.

In my opinion the xc8 compiler works pretty well, also for the PIC10.
Here is an example in C:
#include <xc.h>
#ifndef _XTAL_FREQ
#define _XTAL_FREQ 4000000
#endif
#define Baudrate 1200 //bps
#define OneBitDelay (1000000/Baudrate)
#define DataBitCount 8 // no parity, no flow control
#define UART_RX RA1 // UART RX pin
#define UART_TX RA0 // UART TX pin
#define UART_RX_DIR TRISA1 // UART RX pin direction register
#define UART_TX_DIR TRISA0 // UART TX pin direction register
//Function Declarations
void InitSoftUART(void);
unsigned char UART_Receive(void);
void UART_Transmit(const char);
__CONFIG(FOSC_INTOSC & MCLRE_OFF & WDTE_OFF & LVP_OFF & CP_OFF &
WRT_OFF & PWRTE_OFF & WRT_OFF & BOREN_ON & LPBOR_ON & BORV_LO);
void main()
{
unsigned char ch = 0;
ANSELA = 0x00; // Set ports as digital I/O, not analog input
ADCON = 0x00; // Shut off the A/D Converter
FVRCON = 0x00; // Shut off the Voltage Reference
PORTA = 0x00; // Make all pins 0
InitSoftUART(); // Intialize Soft UART
InitSoftUART(); // Intialize Soft UART
while(1)
{
ch = UART_Receive(); // Receive a character from UART
UART_Transmit(ch); // Echo back that character
}
}
void InitSoftUART(void) // Initialize UART pins to proper values
{
UART_TX = 1; // TX pin is high in idle state
UART_RX_DIR = 1; // Input
UART_TX_DIR = 0; // Output
}
unsigned char UART_Receive(void)
{
// Pin Configurations
// GP1 is UART RX Pin
unsigned char DataValue = 0;
//wait for start bit
while(UART_RX==1);
__delay_us(OneBitDelay);
__delay_us(OneBitDelay/2); // Take sample value in the mid of bit duration
for ( unsigned char i = 0; i < DataBitCount; i++ )
{
if ( UART_RX == 1 ) //if received bit is high
{
DataValue += (1<<i);
}
__delay_us(OneBitDelay);
}
// Check for stop bit
if ( UART_RX == 1 ) //Stop bit should be high
{
__delay_us(OneBitDelay/2);
return DataValue;
}
else //some error occurred !
{
__delay_us(OneBitDelay/2);
return 0x000;
}
}
void UART_Transmit(const char DataValue)
{
/* Basic Logic
TX pin is usually high. A high to low bit is the starting bit and
a low to high bit is the ending bit. No parity bit. No flow control.
BitCount is the number of bits to transmit. Data is transmitted LSB first.
*/
// Send Start Bit
UART_TX = 0;
__delay_us(OneBitDelay);
for ( unsigned char i = 0; i < DataBitCount; i++ )
{
//Set Data pin according to the DataValue
if( ((DataValue>>i)&0x1) == 0x1 ) //if Bit is high
{
UART_TX = 1;
}
else //if Bit is low
{
UART_TX = 0;
}
__delay_us(OneBitDelay);
}
//Send Stop Bit
UART_TX = 1;
__delay_us(OneBitDelay);
}
Source for this code is the :Microchip forum

Related

how use the MPU 6050 in ultra low power mode

I'm currently trying to set up a fermentation specific gravity monitor, using a tilt sensor. The process can take several weeks, and must be contained in a sterile container, so must be battery powerered. I'm using a slightly modified ESP8266-01, which enters sleep mode then wakes once an hour to take a measurement, transmit the data, and return to sleep mode. I'm using an MPU6050 for the tilt sensor. Firstly, I can't seem to put the mpu into sleep mode when the esp is off, it always seems to take around 4mA, and secondly, I only need one axis, is it possible to disable everything else to limit power consumption further? I can't seem to find anything in the manual to disable axis, only to calibrate them. my code is below
experimenting with the registers below seem to make no difference, adding them, taking them out altogether, still takes around 4mA. Tried setting to 1 to put the mpu to sleep at the end of the cycle but makes no difference.
Wire.write(0x6B);
Wire.write(0);
I'm very new to this and im struggling to interpret the manual when it refers to bit6 in addr 6b, how do i set bit 6?
If i could restict the mpu to only 1 axis, no acceleration, and to deep sleep inbetween measurements I should be able to get the power consumption around 0.5mA which gives me agood battery life using a single 18650. Any advice would be greatly appreciated!
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include "MPU6050.h"
#include "I2Cdev.h"
#include "Wire.h"
// Update these with values suitable for your network.
const char* ssid = "****";
const char* password = "******";
IPAddress server(192, 168, 1, 90);
WiFiClient espClient5;
PubSubClient client(espClient5);
long lastMsg = 0;
char msg[50];
const uint8_t scl = 5; //D1
const uint8_t sda = 4; //D2
int val;
int prevVal = 0;
String pubString;
char gravity[50];
MPU6050 mpu;
const int sleepTimeS = 10; //only 10 seconds for testing purposes, set to
1hr when operational
int counter=0;
int16_t ax, ay, az;
int16_t gx, gy, gz;
void setup_wifi() {
delay(10);
// We start by connecting to a WiFi network
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
randomSeed(micros());
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
void callback(char* topic, byte* payload, unsigned int length) { //not
required in this application
}
void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
// Create a random client ID
String clientId = "test";
clientId += String(random(0xffff), HEX);
// Attempt to connect
if (client.connect(clientId.c_str())) {
Serial.println("connected");
// Once connected, publish an announcement...
client.publish("AliveRegister", "FermentMon");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}
#define ONE_WIRE_BUS 2 // D4 on physical board
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature DS18B20(&oneWire);
float prevTemp = 0;
void setup() {
counter = 0;
Serial.begin(9600);
Wire.begin(0,2);
Wire.write(0x6B); //PWR_MGMT_1 register
Wire.write(0); // set to zero wakes teh 6050
Wire.endTransmission(true);
delay(100);
setup_wifi();
client.setServer(server, 1883);
client.setCallback(callback);
if (!client.connected()) {
reconnect();
}
Serial.println("Initialize MPU");
mpu.initialize();
Serial.println(mpu.testConnection() ? "Connected" : "Connection failed");
float temp;
DS18B20.requestTemperatures();
temp = DS18B20.getTempCByIndex(0); // first temperature sensor
char buff[100];
dtostrf(temp, 0, 2, buff);
temp = temp + 0.5;
int tRound = int(temp);
client.publish("Fermenter/temperature", buff);
Serial.print("Fermenter Temperature: ");
Serial.println(temp);
prevTemp = tRound;
mpu.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
val = map(ax, -17000, 17000, 0, 180);
pubString = String(val);
pubString.toCharArray(gravity, pubString.length() + 1);
client.publish("Fermenter/angle", gravity);
Serial.print("Gravity angle: ");
Serial.println(val);
delay(500);
// counter = counter+1;
Serial.println("sleep mode");
Wire.write(0x6B); //PWR_MGMT_1 register
Wire.write(1); // set to zero wakes teh 6050
// sleep
ESP.deepSleep(sleepTimeS * 1000000);
delay(2000);
}
void loop() {
client.loop();
}
I'm very new to this and im struggling to interpret the manual when it refers to bit6 in addr 6b, how do i set bit 6?
Setting a bit is simple.
Use the follow functions to avoid any brain storming.
// Write register bit
void writeRegisterBit(uint8_t reg, uint8_t pos, bool state)
{
uint8_t value;
value = readRegister8(reg);
if (state)
{
value |= (1 << pos);
}
else
{
value &= ~(1 << pos);
}
writeRegister8(reg, value);
}
// Write 8-bit to register
void writeRegister8(uint8_t reg, uint8_t value)
{
Wire.beginTransmission(MPU_addr);
#if ARDUINO >= 100
Wire.write(reg);
Wire.write(value);
#else
Wire.send(reg);
Wire.send(value);
#endif
Wire.endTransmission();
}
Example Usage: writeRegisterBit(MPU6050_REG_INT_PIN_CFG, 5, 1); //Register 37;Interrupt Latch Enable
For your application:
void acclSetSleepEnabled(bool state)
{
writeRegisterBit(MPU6050_REG_PWR_MGMT_1, 6, state);
}
If i could restict the mpu to only 1 axis, no acceleration, and to deep sleep inbetween measurements I should be able to get the power consumption around 0.5mA which gives me agood battery life using a single 18650
To enter low power accelerometer mode use the following function:
void lowPowerAccel(uint8_t frequency) {
uint8_t value;
value = readRegister8(MPU6050_REG_PWR_MGMT_2);
value &= 0b00111000;
value |= (frequency << 6) | 0b111;
writeRegister8(MPU6050_REG_PWR_MGMT_2, value);
value = readRegister8(MPU6050_REG_PWR_MGMT_1);
value &= 0b10010111;
value |= 0b00111000;
writeRegister8(MPU6050_REG_PWR_MGMT_1, value);
}
This lowPowerAccel function also puts the gyro to standy mode. The function needs a wake up frequency parameter.
This is defined as follows:
/*
* LP_WAKE_CTRL | Wake-up Frequency
* -------------+------------------
* 0 | 1.25 Hz
* 1 | 2.5 Hz
* 2 | 5 Hz
* 3 | 10 H
*/
#define LP_WAKE_CTRL_1_25 0x00
#define LP_WAKE_CTRL_2_5 0x01
#define LP_WAKE_CTRL_5 0x02
#define LP_WAKE_CTRL_10 0x03
I hope, I could answer some of your questions.
Good luck! :)
Are you using a breakout board for the MPU6050? e.g. GY-521. Often they use linear regulators and leds which will consume additional power. It may be necessary to remove these and run the IMU from a direct power source.
Each register in the MPU6050 is 8 bits wide. When setting an individual bit to a desired value you can either use bitwise manipulation (not practical here as we aren't directly interacting with the registers) or directly set all of the bits in the register to the register's new state e.g. 0b00100000 ~ 0x20. Instead of writing a 1 to 0x6B when attempting to put the MPU6050 to sleep you should be writing 0x20.
https://www.invensense.com/wp-content/uploads/2015/02/MPU-6000-Register-Map1.pdf
Referencing page 40-42, if you want to take things a step further you can disable the temperature sensor, accelerometers, and redundant gyroscope axes to save power while the device is active.

Issue while reading data from I2c Slave device with PIC16F886

I am newbie to Pic Programming, I am using MPLAb & Hitech compiler to execute above code. I am trying to Interface PIC16F886 with ISL12022M Real time I2C device. i copied code example written for DS1307 interface with 16F887A PIC. I have capable to inteface Basic functionality with above . In below code While write into ISL12022M o could able to see data what i have send in memory register But as when Trying to read rtc time i could able to read last memory write value From SSPBUF. let me know any error in below code.
once I2c read value should be displayed on 4 digit seven segment display.
I think I am doing Misatake in this part. while Reading data i m just sending address so whatever last written in address it displaying.
#include <htc.h>
#include <stdio.h>
#include<pic.h>
#include<stdint.h>
#define _XTAL_FREQ 40000000
unsigned int i=0;
unsigned int k=0;
unsigned int count;
#define Pulse RA5
#define LED RC0
#define LED1 RC2
#define CONTROLREG 0xFF
#define SDA RC4 // Data pin for i2c
#define SCK RC3 // Clock pin for i2c
#define SDA_DIR TRISC4 // Data pin direction
#define SCK_DIR TRISC3 // Clock pin direction
#define DP RA4
#define I2C_SPEED 100 // kbps
unsigned short int cnt, num,Dgt=0;;
unsigned short int temp1,temp2,temp3;
unsigned short sec;
unsigned short min;
unsigned short hour;
unsigned short date;
unsigned short month;
unsigned short year;
unsigned short day;
unsigned short int temp=0;
unsigned short r_data;
#define Seg1 0x01
#define Seg2 0x02
#define Seg3 0x04
#define Seg4 0x08
void SetSeg(unsigned short data, unsigned short segno)
{
switch(data)
{
case 0: PORTB = 0x3F; break;
case 1: PORTB = 0x06; break;
case 2: PORTB = 0x5B; break;
case 3: PORTB = 0x4F; break;
case 4: PORTB = 0x66; break;
case 5: PORTB = 0x6D; break;
case 6: PORTB = 0x7D; break;
case 7: PORTB = 0x07; break;
case 8: PORTB = 0x7F; break;
case 9: PORTB = 0x6F; break;
default : PORTB = 0X00; break;
}
if(segno==1)
{
PORTA = Seg4;
}
if(segno==2)
{
PORTA = Seg3;
}
if(segno==3)
{
PORTA = Seg2;
}
if(segno==4)
{
PORTA = Seg1;
}
}
void Delay(int k)
{
int j;
for(j=0;j<k;j++);
}
void InitI2C(void)
{
SDA_DIR = 1; // Make SDA and
SCK_DIR =0; // SCK pins input
SSPCON = 0b00111000; //enables port for i2c
SSPCON2 = 0b00000000;
SSPADD = 10; // 100KHz = 8MHz/4(SSPADD+1)
// SSPSTAT = 0b11000000; // Slew rate disabled
}
void i2c_waitForIdle(void)
{
unsigned int i2ctimeout;
while(1)
{
i2ctimeout++;
if(i2ctimeout > 10)
{
i2ctimeout = 0;
return;
}
}
}
void I2C_Start(void)
{
SEN = 1; // Send start bit
i2c_waitForIdle();
/* while(!SSPIF); // Wait for it to complete
SSPIF = 0; // Clear the flag bit*/
}
void I2C_ReStart(void)
{
RSEN = 1; // Send Restart bit
i2c_waitForIdle();
/* while(!SSPIF); // Wait for it to complete
SSPIF = 0; // Clear the flag bit
while(RSEN==1);*/
}
void I2C_Stop(void)
{
PEN = 1; // Send stop bit
i2c_waitForIdle();
}
void I2C_Send_ACK(void)
{
ACKDT = 0; // 0 means ACK
ACKEN = 1; // Send ACKDT value
i2c_waitForIdle();
}
void I2C_Send_NACK(void)
{
ACKDT = 1; // 1 means NACK
ACKEN = 1; // Send ACKDT value
i2c_waitForIdle();
}
unsigned char I2C_Write( unsigned char i2cWriteData )
{
i2c_waitForIdle();
SSPBUF = i2cWriteData;
return (!ACKSTAT); // function returns '1'
}
int I2C_Read( unsigned char ack )
{
unsigned char i2cReadData;
//unsigned int i2cReadData;
i2c_waitForIdle();
RCEN = 1;
SDA=1;
SCK=1;
i2c_waitForIdle();
i2cReadData = SSPBUF;
SCK=0;
i2c_waitForIdle();
SCK=1;
if(ack)
{
ACKDT = 0;
}
else
{
ACKDT = 1;
}
ACKEN = 1; // send acknowledge sequence
return( i2cReadData );
}
unsigned int bcdtodecimal(unsigned int bcd)
{
unsigned int decimal;
decimal = (((bcd & 0xF0) >> 4) * 10) + (bcd & 0x0F);
return decimal;
}
void Init_ISL12022M(void)
{
I2C_Start(); // Start I2C communication
I2C_Write(0XD0); //Write Device Address
I2C_Write(0X08); //
I2C_Write(0X41); // Write 0x00 to Control register to disable SQW-Out
I2C_Stop(); // Stop I2C communication after initilizing
}
unsigned int Write_ISL12022M(unsigned short address, unsigned short w_data)
{
I2C_Start(); // Start I2C communication
I2C_Write(0XD0);
I2C_Write(address); //write address to write data
I2C_Write(w_data); //write data into hexadecimal
I2C_Stop();//stop I2C communication
return(w_data);
}
unsigned short Read_ISL12022M(unsigned short address)
{
I2C_Start();
I2C_Write(address); //address 0x68 followed by direction bit (0 for write, 1 for read) 0x68 followed by 0 --> 0xD0
I2C_Write(address);
I2C_ReStart();
I2C_Write(0xD1); //0x68 followed by 1 --> 0xD1
r_data=I2C_Read(0);
I2C_Stop();
return(r_data);
}
void SetDateTime()
{
I2C_Start();
I2C_Write(0xD0);
I2C_Write(0x00);
sec= Write_ISL12022M(0X00, 12); //01 sec
min = Write_ISL12022M(0X01,52); //01 sec
hour = Write_ISL12022M(0X02,9); //01 sec
day= Write_ISL12022M(0X03,7); //01 sec
date = Write_ISL12022M(0X04, 29); //01 sec
month =Write_ISL12022M(0X05,07); //01 sec
year = Write_ISL12022M(0X06,17); //01 sec
I2C_Stop();
}
void RTC_GetDateTime()
{
I2C_Start(); // Start I2C communication
I2C_Send_ACK();
sec = I2C_Read(1); // read second and return Positive ACK
I2C_Send_ACK();
min = I2C_Read(1); // read minute and return Positive ACK
I2C_Send_ACK();
hour= I2C_Read(0); // read hour and return Negative/No ACK
I2C_Send_ACK();
day = I2C_Read(1); // read weekDay and return Positive ACK
I2C_Send_ACK();
date= I2C_Read(1); // read Date and return Positive ACK
I2C_Send_ACK();
month=I2C_Read(1); // read Month and return Positive ACK
I2C_Send_ACK();
year =I2C_Read(0); // read Year and return Negative/No ACK
I2C_Send_ACK();
I2C_Stop(); // Stop I2C communication after reading the Date
}
void interrupt isr(void)
{
if(TMR1IF==1)
{
TMR1H=0xF6; // Load the time value(0xBDC) for 100ms delay
TMR1L=0x18; //Timer1 Interrupt for 65000
TMR1IF=0; // Clear timer interrupt flag
Dgt++;
if(Dgt>=5)
{
Dgt=0;
LED=!LED;
}
}
}
void Timer1_Interrupt()
{
INTCON = 0b00000000;
PIE1=0b00000001;
PIR1=0x01;
TMR1H=0x0B;
TMR1L=0xDC;
T1CON=0x31;
}
void Init_Controller()
{
cnt=100;
TRISC=0b01000000; // Intialize INput & output pheripherals
TRISB=0b10000000;
PORTB = 0b00000000;
TRISA=0b0000000;
ADCON0 = 0b00000000;
ANSEL = 0b00000000;
Timer1_Interrupt();
}
void main(void)
{
Init_Controller();
/* GIE=1;
PEIE=1;
TMR1IE=1; */
InitI2C();
Init_ISL12022M();
SetDateTime();
while(1)
{
RTC_GetDateTime();
SetSeg(year/ 10,2);
SetSeg(year%10,1);
}
}
The lines like:
I2C_Write(0XD0); //Write Device Address
are not a valid device addresses. Use 0xDE (or 0xAE for User SRAM)
From the datasheet:
Following a start condition, the master must output a Slave Address Byte. The 7 MSBs are the device identifiers. These bits are “1101111” for the RTC registers and “1010111” for the User SRAM.

ATMega2560 PCINT Interrupts

i am new to Atmel, so maybe the question is quite simple.
I have the following situation:
I have an ATMega2560 and want to get Interrupts on the Pins PK0-PK7. I am interested in the PIN Change from Low to HIGH. (I have connected one photocell to every PIN)
I have read that the interrupt for PCINT[0-2] are fired everytime (pin high and pin low) so i defined an array to ignore the PIN DOWN Interrupt.
So i have the following code:
Note: I do not understand, why i need to set DDRC as input and not DDRK ?
#define HIGH 1
#define LOW 0
volatile uint8_t portbhistory = 0xFF;
uint8_t pinState[8];
void initSystem()
{
int i;
for(i = 0; i < sizeof(pinState) / sizeof(*pinState); i++)
{
pinState[8] = 0;
}
DDRB = 0xff; // set Port B as output
DDRC = 0; // WHY DDRC ?? PCINT == PK0-7, so DDRK ? // all Pins input
PORTC = 0xff; // same question ... // turn on pullup for every pin
PCICR |= _BV(PCIE2); // enable interrupt for PCIE2
PCMSK2 = 0xff; // Interrupt at all pins
sei(); // turn on interrupts
}
int main(void)
{
initSystem();
while(1)
{
}
}
ISR(PCINT2_vect)
{
int i;
uint8_t changedbits;
changedbits = PINC ^ portbhistory;
portbhistory = PINC;
/*
if(pinState[changedbits] == HIGH)
{
pinState[changedbits] = LOW;
return;
} else
{
pinState[changedbits] = HIGH;
}
*/
setDebugLED(1);
_delay_ms(30);
setDebugLED(0);
}
If i connect 5V to one of the PINS (PK0-7) the LED flashes instantly. But if i disconnect the 5V it takes ~2seconds for the LED to flash again. In this time the one pin i connected 5V before does not let the LED flash again if i connect the 5 V again.
Other Ports work in this time.
So you could say, that the PIN HIGH interrupt for all pins work fine and get fired instantly but the PIN LOW interrupts need some time (~2sec.) In this time the port is "disabled" or somethig.
Can anyone help me with that?
EDIT
Just some wrong edit ...
EDIT 2
So, i totally forgot to post my solution here. sorry for that!
The solution is: My external circuit pulls the PIN to Ground or to 5V.
Thank you!

No output on pins in pic24f

I can't get my pic24f04kl100 to turn on an LED at all. The below code is as simple as possible and it still doesn't turn on the LED on pin 6.
Code
#include <xc.h>
#define LED LATBbits.LATB4
#define LEDans ANSBbits.ANSB4
#define LEDtris TRISBbits.TRISB4
/* Setting up configuration bits */
_FOSCSEL(FNOSC_FRCPLL & IESO_OFF); // FRC w/PLL and int./ext. switch disabled
_FOSC(POSCMD_XT & FCKSM_CSECMD); // Pri. OSC XT mode and clk. switch on, fail-safe off
_FWDT(FWDTEN_OFF); // Watchdog timer off
void initialise();
void delay(int i);
void main() { // Main program loop
initialise(); // Intialise PIC
while (1) { // Infinite loop
LED = 1; // Set LED high
LED = 0; // Set LED low
}
}
void initialise() { // Configures the PIC
OSCCONbits.NOSC = 0b111; // Fast RC Oscillator with Postscaler and PLL module
delay(100);
CLKDIVbits.RCDIV = 0b000; // Set clock div 1:1
delay(100);
LEDans = 0;
delay(100);
LEDtris = 0; // Make LED an output
delay(100);
LED = 0; // Set LED low
}
void delay(int i) {
while(i--);
}
PICkit 3 Output
*****************************************************
Connecting to MPLAB PICkit 3...
Firmware Suite Version.....01.27.04
Firmware type..............dsPIC33F/24F/24H
Target detected
Device ID Revision = 0
The following memory area(s) will be programmed:
program memory: start address = 0x0, end address = 0x3ff
configuration memory
Programming...
Programming/Verify complete
By default B4 pin is analog. Configure it as digital by clearing the ANSB register, bit4
NOTE: Although clearing the bit DID NOT fix the problem. Moving to another pin (with less features) did. So I (fossum) made the assumption that this was at least on some level the correct answer.
The LED is blinking, but it's blinking very fast, try to put some delay between LED turn on and LED turn off.
Try this:
void main() { // Main program loop
initialise(); // Intialise PIC
while (1) { // Infinite loop
LED = 1; // Set LED high
delay(50000); //wait LED on time
LED = 0; // Set LED low
delay(50000); //wait LED off time
}
}

pwm value not changing

I have written a pwm code for Atmega128. I am using fast pwm mode with non-inverting pulse on compare match and I need to change the OCR0 value at certain times. Yet it doesn't change. Anyone knows what is the problem here ??
#include <avr/interrupt.h>
#include <avr/io.h>
uint8_t tick_1sec;
void timer1_init(void) // 1 second timer
{
OCR1A = 15624;
TIMSK |= (1<<OCIE1A);
TCCR1B = (1<<WGM12); //CTC mode
TCCR1B |= (1<<CS12)|(0<<CS11)|(1<<CS10);
}
ISR(TIMER1_COMPA_vect) //1 second interrupt
{
cli();
tick_1sec = 1;
sei();
}
void timer0_init(void) // fast pwm with OC0 non-inverting mode
{
TCCR0 = (1<<FOC0)|(1<<WGM01)|(1<<WGM00);
TCCR0 |= (1<<COM01)|(0<<COM00);
TCCR0 |= (1<<CS02)|(1<<CS01)|(1<<CS00);
OCR0 = 63;
TIMSK |= (1<<OCIE0);
}
int main(void)
{
uint8_t t = 0;
DDRB = 0xFF;
timer0_init();
timer1_init();
sei();
while(1){
if (tick_1sec)
{
tick_1sec = 0;
t++;
if (t == 10){
OCR0 = 127;
}
else if (t == 20){
OCR0 = 191;
}
else if (t == 30){
OCR0 = 63;
t = 0;
}
}
}
return 0;
}
Things to check:
I recommend declaring tick_1sec as volatile to prevent the compiler of hyper-optimizing that register.
What is your clock frequency? Your ISR will deliver 1s calls only if your CPU frequency is 16MHz (==> 16.000.000 / 1024 / 15624)
You might have a LED in your hardware which you can invert from a) the ISR b) within the first if () in main to see if this is ever reached.
update: "volatile"
The link provided by #skyrift in his comment is very worth reading.
When you use Atmel Studio, compile your code once with/without the volatile keyword and compare what the compiler is doing ==> Solution explorer / Output Files / *.lss ... you will see each C statement and how the compiler converts it to machine code ... an exercise worth once in a while when working with micros ...

Resources