|
|
View previous topic :: View next topic |
Author |
Message |
stratogama
Joined: 03 Sep 2015 Posts: 2
|
PWM controlled through I2C BH1750 |
Posted: Fri Dec 11, 2015 1:17 pm |
|
|
Hello everyone, I'm trying to drive my lights through BH1750 module.
This device uses I2C to communicate with microcontrollers. The idea is to exploit to the maximum ambient light and then the electric light, to do this, first I measure the light of my lamp with the maximum duty cycle to define a preset value, then reduce it to a minimum duty cycle. After all this, I make an infinite loop in which I measure the ambient brightness and compare this value with the preset value and then reduce or increase the duty cycle.
But when I test on the circuit this does not work.
I tested the modules separately and works perfectly, but together only works until the part of the while loop.
I hope you can help me and give me some advice please.
Here my code:
Code: | #include <16f877a.h>
#use delay (clock=20000000)
#fuses HS
#fuses NOWDT
#fuses NOLVP
#fuses NOPROTECT
#use I2C(MASTER, sda=PIN_C4, scl=PIN_C3)
#define PWR_DOWN 0x00
#define PWR_ON 0x01
#define RESET 0X07
#define MODE_HIGH_RES1 0X10
#define MODE_HIGH_RES2 0X11
#define MODE_LOW_RES 0x13
#define ADDR_HIGH_R 0xB9
#define ADDR_HIGH_W 0xB8
#define ADDR_LOW_R 0X47
#define ADDR_LOW_W 0x46
unsigned long MUESTRA,LUX,PWM,PRESET;
char HB,LB;
//funcion para activar y configurar el modulo sensor de luminosidad
void BH1750_init()
{
I2C_START();
I2C_WRITE(ADDR_LOW_W);
I2C_WRITE(PWR_ON);
I2C_WRITE(RESET);
I2C_WRITE(ADDR_LOW_W);
I2C_WRITE(MODE_HIGH_RES1);
I2C_STOP();
delay_ms(100);
}
void main()
{
//configuro canal PWM y BH1750
setup_ccp1(CCP_PWM);
setup_timer_2(T2_DIV_BY_4,83,1);
BH1750_init();
//inicio canal PWM en 0 y luego lo subo al 99% aprox.
set_pwm1_duty(0L);
set_pwm1_duty(82L);
//guardo la maxima luminosidad de la luminaria en PRESET
I2C_START();
I2C_WRITE(ADDR_LOW_R);
HB=I2C_READ(1);
LB=I2C_READ(0);
I2C_STOP();
MUESTRA=make16(HB,LB);
PRESET=(MUESTRA/1.2);
//bajo el valor del PWM a 0, como al inicio
set_pwm1_duty(0L);
while(1)
{
I2C_START();
I2C_WRITE(ADDR_LOW_R);
HB=I2C_READ(1);
LB=I2C_READ(0);
I2C_STOP();
MUESTRA=make16(HB,LB);
LUX=(MUESTRA/1.2);
PWM=0;
if(LUX<PRESET)
{
PWM=PWM+1;
set_pwm1_duty(PWM);
}
else if(LUX>PRESET)
{
PWM=PWM-1;
set_pwm1_duty(PWM);
}
}
}
|
And my scheme:
http://imageshack.com/a/img911/1525/48xw6Q.png |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Dec 11, 2015 1:47 pm |
|
|
Quote: | but together only works until the part of the while loop. |
What does this mean ? Give more details on what it is doing when it fails.
Add some printf statements to display the status of your program
while it's running. See the lines in bold below. If you put in these
debug statements, you will be able to see the problems in your code.
Display the printf output in a terminal program such as TeraTerm.
Quote: |
#include <16f877a.h>
#fuses HS
#fuses NOWDT
#fuses NOLVP
#fuses NOPROTECT
#use delay (clock=20000000)
#use rs232(9600, UART1, ERRORS)
.
.
.
while(1)
{
I2C_START();
I2C_WRITE(ADDR_LOW_R);
HB=I2C_READ(1);
LB=I2C_READ(0);
I2C_STOP();
MUESTRA=make16(HB,LB);
LUX=(MUESTRA/1.2);
printf("Lux = %lu, Preset = %lu \n\r", LUX, PRESET);
PWM=0;
if(LUX<PRESET)
{
PWM=PWM+1;
printf("Low Lux. New PWM duty = %lu \n\r", PWM);
set_pwm1_duty(PWM);
}
else if(LUX>PRESET)
{
PWM=PWM-1;
printf("High Lux. New PWM duty = %lu \n\r", PWM);
set_pwm1_duty(PWM);
}
printf("\n\r");
delay_ms(500);
}
|
Also, the preferred style for C is that code (function names, variables, etc.) is in lower case, and constants ( #define VALUES) are in upper case. It makes the source code easier to understand quickly. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9245 Location: Greensville,Ontario
|
|
Posted: Fri Dec 11, 2015 7:59 pm |
|
|
just a note...
PRESET=(MUESTRA/1.2);
You've defined both variables as unsigned long yet do a floating point divide..
I'm thinking that the compiler WILL do a FP divide then cast back into 16 bit int for you...but...better check....
also FP math is very time consuming ! Better to use 'scaled integers' or similar integer math, could easily be 5-10X faster asn just as accurate...
Jay |
|
|
stratogama
Joined: 03 Sep 2015 Posts: 2
|
PWM controlled through I2C BH1750 |
Posted: Sat Dec 12, 2015 12:26 am |
|
|
Hello again, thanks for your replies, PCM programmer when I turn on the circuit, the I2C communication works and then the PWM start at 0%, then it rises to 99% and then turns 0% again, the I2C still works I tested it with my oscilloscope but the PWM does nothing, tested with the oscilloscope too.
So, I have tried what you said, but with an lcd instead of teraterm and I have obtained the following:
PRESET=0
LUX=0
PWM doesn't shown
But surprisingly, after a few minutes I obtain this:
PRESET=0
LUX=42
PWM=65365
Here is the code with the printf statements and the lcd:
Code: |
#include <16f877a.h>
#use delay (clock=20000000)
#fuses HS
#fuses NOWDT
#fuses NOLVP
#fuses NOPROTECT
#include <lcd.c>
#define LCD_ENABLE_PIN PIN_D0
#define LCD_RS_PIN PIN_D1
#define LCD_RW_PIN PIN_D2
#define LCD_DATA4 PIN_D4
#define LCD_DATA5 PIN_D5
#define LCD_DATA6 PIN_D6
#define LCD_DATA7 PIN_D7
#use I2C(MASTER, sda=PIN_C4, scl=PIN_C3)
#define PWR_DOWN 0x00
#define PWR_ON 0x01
#define RESET 0X07
#define MODE_HIGH_RES1 0X10
#define MODE_HIGH_RES2 0X11
#define MODE_LOW_RES 0x13
#define ADDR_HIGH_R 0xB9
#define ADDR_HIGH_W 0xB8
#define ADDR_LOW_R 0X47
#define ADDR_LOW_W 0x46
unsigned long MUESTRA1,MUESTRA2,LUX,PWM,PRESET;
char HB,LB;
//funcion para activar y configurar el modulo sensor de luminosidad
void BH1750_init()
{
I2C_START();
I2C_WRITE(ADDR_LOW_W);
I2C_WRITE(PWR_ON);
I2C_WRITE(RESET);
I2C_WRITE(ADDR_LOW_W);
I2C_WRITE(MODE_HIGH_RES1);
I2C_STOP();
delay_ms(100);
}
void main()
{
//configuro canal PWM y BH1750
lcd_init();
setup_ccp1(CCP_PWM);
setup_timer_2(T2_DIV_BY_4,83,1);
BH1750_init();
//inicio canal PWM en 0 y luego lo subo al 99% aprox.
set_pwm1_duty(0L);
set_pwm1_duty(82L);
//guardo la maxima luminosidad de la luminaria en PRESET
I2C_START();
I2C_WRITE(ADDR_LOW_R);
HB=I2C_READ(1);
LB=I2C_READ(0);
I2C_STOP();
MUESTRA1=make16(HB,LB);
PRESET=(MUESTRA1/1.2);
lcd_putc("\f");
lcd_gotoxy(1,1);
printf(lcd_putc,"PRESET=%lu",PRESET);
//bajo el valor del PWM a 0, como al inicio
set_pwm1_duty(0L);
while(1)
{
I2C_START();
I2C_WRITE(ADDR_LOW_R);
HB=I2C_READ(1);
LB=I2C_READ(0);
I2C_STOP();
MUESTRA2=make16(HB,LB);
LUX=(MUESTRA2/1.2);
lcd_gotoxy(1,2);
printf(lcd_putc,"LUX=%lu",LUX);
PWM=0;
if(LUX<PRESET)
{
PWM=PWM+1;
set_pwm1_duty(PWM);
lcd_gotoxy(8,2);
printf(lcd_putc,"PWM=%lu",PWM);
}
else if(LUX>PRESET)
{
PWM=PWM-1;
set_pwm1_duty(PWM);
lcd_gotoxy(8,2);
printf(lcd_putc,"PWM=%lu",PWM);
}
}
}
|
Jay, I understand what you said, but I don't know how to check it, I'm still a noob. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
Re: PWM controlled through I2C BH1750 |
Posted: Mon Dec 14, 2015 10:46 am |
|
|
stratogama wrote: |
So, I have tried what you said, but with an lcd instead of teraterm and I
have obtained the following:
PRESET=0
LUX=0
PWM doesn't show
|
Look at your code below. You don't have an if() statement that covers
the case where LUX == PRESET. You initially set PWM = 0. If LUX == 0,
then both if() statements below will be ignored. PWM will not show.
Code: |
PWM=0;
if(LUX<PRESET)
{
PWM=PWM+1;
set_pwm1_duty(PWM);
lcd_gotoxy(8,2);
printf(lcd_putc,"PWM=%lu",PWM);
}
else if(LUX>PRESET)
{
PWM=PWM-1;
set_pwm1_duty(PWM);
lcd_gotoxy(8,2);
printf(lcd_putc,"PWM=%lu",PWM);
}
|
So the question is, why does LUX stay at 0 ? Maybe there is something
wrong with your hardware design. Or your software driver for the BH1750 ?
stratogama wrote: |
the I2C still works I tested it with my oscilloscope |
I would test the i2c by running the BH1750 driver and looking at the
lux values returned by the driver. I would not use an LCD for this.
I would use RS232 and TeraTerm (or some other terminal program).
When you use a terminal program, it displays a record of the past values.
You can examine the data carefully. With an LCD, there is no past
record. There are not enough lines in the LCD for it.
stratogama wrote: |
But surprisingly, after a few minutes I obtain this:
PRESET=0
LUX=42
PWM=65365
|
It's not that surprising. If LUX is greater than PRESET, the 'PWM'
variable will decrement by 1. It will go from 0 to -1, which is 0xFFFF,
which is 65535. And PRESET is 0, so if LUX goes to 1 or anything, you
will get 65535 as the PWM value.
If LUX remains > 0, then PWM will continue to decrement, and you will
get PWM=65365 at some point.
The lines in bold below show this:
Quote: |
PWM=0;
if(LUX<PRESET)
{
PWM=PWM+1;
set_pwm1_duty(PWM);
lcd_gotoxy(8,2);
printf(lcd_putc,"PWM=%lu",PWM);
}
else if(LUX>PRESET) // if LUX > 0
{
PWM=PWM-1;
set_pwm1_duty(PWM);
lcd_gotoxy(8,2);
printf(lcd_putc,"PWM=%lu",PWM);
}
} |
|
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|