|
|
View previous topic :: View next topic |
Author |
Message |
rosiley
Joined: 29 May 2014 Posts: 18 Location: Brasil
|
Help. As I stabilize last digit with max7219 |
Posted: Tue Feb 28, 2017 7:34 am |
|
|
Hi everyone, I have a problem here, my code is works normally, but the last digit does not stabilize it oscillates +/- 5 mv. I am using 18f4553 configured for 12 bits with max7219.
I used this code.
Code: |
//=========================Variaveis do MAX7219 veja Datasheet================\\
#define NO_OP 0x00 // Used when cascading max7221s
#define DIGIT_0 0x01 // Digit 0 register
#define DIGIT_1 0x02 // Digit 1 register
#define DIGIT_2 0x03 // Digit 2 register
#define DIGIT_3 0x04 // Digit 3 register
#define DIGIT_4 0x05 // Digit 4 register
#define DIGIT_5 0x06 // Digit 5 register
#define DIGIT_6 0x07 // Digit 6 register
#define DIGIT_7 0x08 // Digit 7 register
#define DECODE_MODE 0x09 // Decode mode register
#define INTENSITY 0x0A // Intensity register
#define SCAN_LIMIT 0x0B // Scan-limit register
#define SHUT_DOWN 0x0C // Shutdown register
#define DISPLAY_TEST 0x0F // Display-test register
// Shutdown register
#define SHUTDOWN_MODE 0x00 // Shutdown mode
#define NORMAL_MODE 0x01 // Normal mode
// Decode-mode register
#define NO_DECODE_DIGITS_7_0 0x00 // No decode for digits 7-0
#define CODE_B_DECODE_DIGIT_0 0x01 // Code B decode for digit 0
#define CODE_B_DECODE_DIGITS_3_0 0x0F // Code B decode for digits 3-0
#define CODE_B_DECODE_DIGITS_7_0 0xFF // Code B decode for digits 7-0
// Intensity register
#define DUTY_CYCLE_1 0x00 // Intensity min
#define DUTY_CYCLE_2 0x01
#define DUTY_CYCLE_3 0x02
#define DUTY_CYCLE_4 0x03
#define DUTY_CYCLE_5 0x04
#define DUTY_CYCLE_6 0x05
#define DUTY_CYCLE_7 0x06
#define DUTY_CYCLE_8 0x07
#define DUTY_CYCLE_9 0x08
#define DUTY_CYCLE_10 0x09
#define DUTY_CYCLE_11 0x0A
#define DUTY_CYCLE_12 0x0B
#define DUTY_CYCLE_13 0x0C
#define DUTY_CYCLE_14 0x0D
#define DUTY_CYCLE_15 0x0E
#define DUTY_CYCLE_16 0x0F // Intensity full
// Scan-limit register
#define DISPLAY_DIGIT_0 0x00 // Display digit 0
#define DISPLAY_DIGITS_01 0x01 // Display digits 0 1
#define DISPLAY_DIGITS_012 0x02 // Display digits 0 1 2
#define DISPLAY_DIGITS_0123 0x03 // Display digits 0 1 2 3
#define DISPLAY_DIGITS_01234 0x04 // Display digits 0 1 2 3 4
#define DISPLAY_DIGITS_012345 0x05 // Display digits 0 1 2 3 4 5
#define DISPLAY_DIGITS_0123456 0x06 // Display digits 0 1 2 3 4 5 6
#define DISPLAY_DIGITS_01234567 0x07 // Display digits 0 1 2 3 4 5 6 7
// Display-test register
#define NORMAL_OPERATION 0x00 // Operação Normal
#define DISPLAY_TEST_MODE 0x01 // Display-test mode, todos leds ON
void SPI_MAX7219(unsigned char dato); /* Declaramos a função que nos permitirá
/ enviar os dados de escrita no MAX*/
void Comandos_MAX7219(unsigned char direc,unsigned char dato ); /* Função exclusiva
para enviar comandos */
void Init_MAX7219(unsigned char decode);// 0xFF o 0x00 (Ativa ou desativa o decodificador)
void Write_MAX7219(unsigned char num,unsigned char direc,unsigned char dato );
Void SPI_MAX7219( unsigned char dato){
int con;
for(con=8;con>0;con--)
{
output_low(MAX_CLK);
if(bit_test(dato,con-1)==0)
output_low(MAX_DIN);
else
output_high(MAX_DIN);
output_high(MAX_CLK);
}
}
void Comandos_MAX7219(unsigned char direc,unsigned char dato )
{
unsigned char cont;
output_low(MAX_LOAD);
for(cont=0; cont<N_MAX;cont++)
{
SPI_MAX7219(direc);
SPI_MAX7219(dato);
}
output_high(MAX_LOAD);
}
void Init_MAX7219(unsigned char decode)
{
output_low(MAX_DIN);
output_low(MAX_CLK);
output_high(MAX_LOAD);
Comandos_MAX7219(0x09,decode);// Desativamos o modo DECODER
Comandos_MAX7219(0x0A,0x01); // Ajustamos o PWM 21/32
Comandos_MAX7219(0x0c,0x00); // Desativamos o MAX
Comandos_MAX7219(0x0B,0x05); // Ajustamos o Scaneo que será de DIG0 a DIG5
Comandos_MAX7219(0x0c,0x01); // Desativamos o MAX
Comandos_MAX7219(0x0F,0x00); // Desativamos o TEST
Comandos_MAX7219(0x0C,0x01); // Ativamos o MAX
}
void Write_MAX7219(unsigned char num,unsigned char direc,unsigned char dato )
{
unsigned char MAX_DATO[10]={0,0,0,0,0,0,0,0,0,0};
unsigned char rep;
unsigned char cont;
rep = N_MAX*2;
MAX_DATO[num*2-1]=direc;
MAX_DATO[num*2-2]=dato;
output_low(MAX_LOAD);
for(cont=rep; cont>0;cont--)
{
SPI_MAX7219(MAX_DATO[cont-1]);
}
output_high(MAX_LOAD);
}
|
Code: |
#include "UDAD_main.h"
#include "MAX7219.C"
/*==============================================================================
CANAL RA0 PIN 2 ANALOGUE INPUT 1 - lblsensor 1
==============================================================================*/
void ADCinput0()
{
set_adc_channel(0);
delay_us(10);
ADinput0 = READ_ADC();
AD0 = (ADinput0 * 5000) /4095;
printf("1@1%04lu",AD0); //Envia dados de conversão A/D para exibir tensão
printf("7");
Write_MAX7219(1,1, 0b0101010); //milhar
Write_MAX7219(1,2, AD0/1000| 0b10000000); //centena
Write_MAX7219(1,3,(AD0%1000)/100); //dezena
Write_MAX7219(1,4,(AD0%100)/10); //unidade
Write_MAX7219(1,5, AD0%10);
Write_MAX7219(1,6, AD0%1);
}
|
Code: |
void main()
{
setup_adc_ports(AN0_TO_AN9|VSS_VDD);
setup_adc(ADC_CLOCK_DIV_32);
enable_interrupts(GLOBAL);
enable_interrupts(INT_RDA);
enable_interrupts(INT_TIMER0);
setup_psp(PSP_DISABLED);
setup_wdt(WDT_OFF);
setup_timer_0(RTCC_INTERNAL | RTCC_DIV_256 | RTCC_8_BIT);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_timer_3(T3_DISABLED|T3_DIV_BY_1);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
set_timer0(61);
output_D(0X00);
backlight = input_state(PIN_D7);
/*===========================================================================
HABILITA O DRIVER MAX7219
===========================================================================*/
//Decode Mode Enable
Init_MAX7219(0xFF);
delay_ms(1000);
/*===========================================================================
LOOP PRINCIPAL
===========================================================================*/
while (true)
{
/*===================DIRETIVAS ENTRADAS ANALÓGICAS===================*/
ADCinput0();
|
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19552
|
|
Posted: Tue Feb 28, 2017 8:39 am |
|
|
Honestly, VSS_VDD.
You are unlikely to be able to get better than 8bit useable resolution using the supply as your reference. Every time the PIC does something (particularly things like switching displays drawing some current), the supply _will_ ripple. Even the best regulator takes time to correct.
To honestly get a really useable 12bit resolution requires really careful design of all the circuitry involved, a good reference, and good PCB layout. |
|
|
rosiley
Joined: 29 May 2014 Posts: 18 Location: Brasil
|
|
Posted: Tue Feb 28, 2017 8:54 am |
|
|
Okay, but my code reads a value that at the moment is varying from 1,045 mv to 1,048 on the last digit and the source is well stabilized, not showing any variation right now. The values of thousand, hundred and ten are ok, only the units are that they vary. |
|
|
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
|
Posted: Tue Feb 28, 2017 9:06 am |
|
|
rosiley wrote: | Okay, but my code reads a value that at the moment is varying from 1,045 mv to 1,048 on the last digit and the source is well stabilized, not showing any variation right now. The values of thousand, hundred and ten are ok, only the units are that they vary. | You're being asked the question:-
How do you KNOW that BOTH the source and the reference are sufficiently well stabilised?
Mike |
|
|
rosiley
Joined: 29 May 2014 Posts: 18 Location: Brasil
|
|
Posted: Tue Feb 28, 2017 9:13 am |
|
|
I have here a multimeter and it show me a value around 5.01 volts.
At this moment I'm switching the reference source to an adjustable one to see what happens. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19552
|
|
Posted: Tue Feb 28, 2017 9:31 am |
|
|
Wrong answer I'm afraid....
A multimeter _integrates_ the signal. Most (unless you pay a lot of money for high speed meters from somebody like Fluke), will not see signals above a very few Hz. Most cheaper ones have update rates of only about 4Hz. Problem is that the noise you are likely to have is high frequency.
Also you say '5.01', A 12bit ADC, running off 5v will have a resolution of 1.2mV/ step. You need at least 3 decimal places after the '5', to see this type of signal.
Just switching the source, won't help unless the source you have is a really high stability type. and the ground layout around the circuit is good |
|
|
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
|
Posted: Tue Feb 28, 2017 9:37 am |
|
|
rosiley wrote: | I have here a multimeter and it show me a value around 5.01 volts.
At this moment I'm switching the reference source to an adjustable one to see what happens. | Like Mr T. says, there's more to it than your DVM can show.
I'd be having a look around with an AC coupled scope for starters.
Could be very revealing.
Mike
I see Mr T. got in as I typed, adds to my comments. |
|
|
rosiley
Joined: 29 May 2014 Posts: 18 Location: Brasil
|
|
Posted: Tue Feb 28, 2017 9:43 am |
|
|
Testing here I verified that my reference was not good, I changed it and I improved the code now I already have a variation around 1 mv that is acceptable for the proposed circuit. I will improve the layout of the circuit because it is mounted on a prototype board without much filtering. |
|
|
rosiley
Joined: 29 May 2014 Posts: 18 Location: Brasil
|
|
Posted: Tue Feb 28, 2017 9:47 am |
|
|
My problem was really in the reference voltage, I'm going to use a tl431 to make the reference and I think I should solve my problem. And in the final circuit I will use precision resistor so everything is the way I want it. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19552
|
|
Posted: Tue Feb 28, 2017 9:55 am |
|
|
Good.
Now as a comment, to improve things (but you do need to be starting with something worth improving...), look at averaging.
One 'classic' is Olympic averaging:
Code: |
int16 sum,temp;
int16 max,min;
int8 ctr;
max=0;
min=4096;
sum=0;
for (ctr=0;ctr<6;ctr++)
{
delay_us(5);
temp=read_adc();
sum+=temp; //add six
if (temp>max) //record if this is a new 'max' value
max=temp;
if (temp<min) //same if this is a new 'min' value
min=temp;
}
sum-=max;
sum-=min; //now subtract the max and min
//now if you use sum/4 you will get a very good average
|
You get the average of the four 'middle' readings. This is the basis of the scoring system used in Olympic events where they have a jury of (say) five members, and reject the highest and lowest scores. It's a very powerful way of quite quickly getting an average, and rejecting 'extreme' values. Using a count that requires a 'binary' division at the end (6, or 10 readings say), makes the code very fast, since on an integer /4 /8 etc., can be done by simple rotation. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19552
|
|
Posted: Tue Feb 28, 2017 9:58 am |
|
|
A TL431 is not really a precision reference. For a 12bit ADC, you need something like a X60008-41 (4.096v reference).
Different 'class' I'm afraid. |
|
|
|
|
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
|