/************************** MMC Init **************************************/
/* Initialises the MMC into SPI mode and sets block size, returns 0 on success */
int mmc_init()
{
int i;
SETUP_SPI(SPI_MASTER | SPI_H_TO_L | SPI_CLK_DIV_4 | SPI_SS_DISABLED);
*0x94 |= 0x40; // set CKE = 1 - clock idle low
*0x14 &= 0xEF; // set CKP = 0 - data valid on rising edge
OUTPUT_HIGH(PIN_C2); // set SS = 1 (off)
for(i=0;i<10;i++) // initialise the MMC card into SPI mode by sending clks on
{
SPI_WRITE(0xFF);
}
OUTPUT_LOW(PIN_C2); // set SS = 0 (on) tells card to go to spi mode when it receives reset
SPI_WRITE(0x40); // send reset command
SPI_WRITE(0x00); // all the arguments are 0x00 for the reset command
SPI_WRITE(0x00);
SPI_WRITE(0x00);
SPI_WRITE(0x00);
SPI_WRITE(0x95); // precalculated checksum as we are still in MMC mode
puts("Sent go to SPI\n\r");
if(mmc_response(0x01)==1) return 1;
// if = 1 then there was a timeout waiting for 0x01 from the mmc
puts("Got response from MMC\n\r");
i = 0;
while((i < 255) && (mmc_response(0x00)==1)) // must keep sending command if response
{
SPI_WRITE(0x41); // send mmc command one to bring out of idle state
SPI_WRITE(0x00); // all the arguments are 0x00 for command one
SPI_WRITE(0x00);
SPI_WRITE(0x00);
SPI_WRITE(0x00);
SPI_WRITE(0xFF); // checksum is no longer required but we always send 0xFF
i++;
}
if(i >= 254) return 1; // if >= 254 then there was a timeout waiting for 0x00 from the mmc
puts("Got out of idle response from MMC\n\r");
OUTPUT_HIGH(PIN_C2); // set SS = 1 (off)
SPI_WRITE(0xFF); // extra clocks to allow mmc to finish off what it is doing
OUTPUT_LOW(PIN_C2); // set SS = 0 (on)
SPI_WRITE(0x50); // send mmc command one to bring out of idle state
SPI_WRITE(0x00);
SPI_WRITE(0x00);
SPI_WRITE(0x02); // high block length bits - 512 bytes
SPI_WRITE(0x00); // low block length bits
SPI_WRITE(0xFF); // checksum is no longer required but we always send 0xFF
if((mmc_response(0x00))==1) return 1;
OUTPUT_HIGH(PIN_C2); // set SS = 1 (off)
puts("Got set block length response from MMC\n\r");
return 0;
}
/************************** MMC Write Block *******************************/
int mmc_write_block(unsigned long block_number)
{
unsigned long i;
unsigned long varh,varl;
char p,f,n;
set_adc_channel(0);
delay_us(10);
f=read_adc();
n=(f*5)/256;
p=(n*9375)/206;
varl=((block_number&0x003F)<<9);
varh=((block_number&0xFFC0)>>7);
puts("Write block\n\r"); // block size has been set in mmc_init()
OUTPUT_LOW(PIN_C2); // set SS = 0 (on)
SPI_WRITE(0x58); // send mmc write block
SPI_WRITE(varh);
SPI_WRITE(varl);
SPI_WRITE(0x00); // always zero as mulitples of 512
SPI_WRITE(0xFF); // checksum is no longer required but we always send 0xFF
if((mmc_response(0x00))==1) return 1;
puts("Got response to write block\n\r");
SPI_WRITE(0xFE); // send data token
for(i=0;i<512;i++)
{
SPI_WRITE(p); // send data
}
SPI_WRITE(0xFF); // dummy CRC
SPI_WRITE(0xFF);
if((SPI_READ(0xFF)&0x0F)!=0x05) return 1;
puts("Got data response to write block\n\r");
OUTPUT_HIGH(PIN_C2); // set SS = 1 (off)
return 0;
}
/************************** MMC get response *******************************/
/**** Repeatedly reads the MMC until we get the response we want or timeout ****/
int mmc_response(unsigned char response)
{
unsigned long count = 0xFFFF;
// 16bit repeat, it may be possible to shrink this to 8 bit but there is not much point
while(SPI_READ(0xFF) != response && --count > 0);
if(count==0) return 1; // loop was exited due to timeout
else return 0; // loop was exited before timeout
}
/**************************************************************************/
It is most probable that he left-justified the A/D result instead of using right-justified.
With left justified, the ADRESH contains the 8 significant bits of the 10-bit A/D, and the ADRESL contains the 2 least significant bits.
Your application code can still obtain the equivalent voltage by reading only the ADRESH and ignoring the ADRESL.
But the reading has lost 2 bits of accuracy. If you application can tolerate it, then its ok.
The resulting code, however, is simpler and faster since you only have to divide by 256 instead of 1024.
So its a trade-off.
Just one step: clear the ADFM bit (ADCON1<7>) to use the left-justified A/D result.
In your code, just read the ADRESH register.
adc_val = ADRESH;
voltage = (adc_val / 256.0) * 5.0;
#include<16f877a.h>
#fuses hs,nowdt, noprotect, nolvp
#use delay(clock=10000000)
#include<math.h>
#include<string.h>
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#define lcd_e1 pin_d7
#define lcd_rs1 pin_d6
#define lcd_port output_b
#define lcd_direction set_tris_b
#define lcd_command set_tris_c
int mmc_init();
int mmc_response(unsigned char response);
int mmc_write_block(unsigned long block_number);
void init_lcd();
void putdata_lcd(int valued);
void erase_lcd();
void putcmd_lcd(int valuec);
void goto_lcd(int x, int y);
void put_string_lcd(char v[16]);
/************************** MMC Init **************************************/
/* Initialises the MMC into SPI mode and sets block size, returns 0 on success */
int mmc_init()
{
}
/************************** MMC Write Block *******************************/
int mmc_write_block(unsigned long block_number)
{
}
/************************** MMC get response *******************************/
/**** Repeatedly reads the MMC until we get the response we want or timeout ****/
int mmc_response(unsigned char response) { }
/**************************************************************************/
/************************************ LCD ** *******************************/
void init_lcd() {}
void putdata_lcd(int valued) {}
void erase_lcd() { }
void putcmd_lcd(int valuec) { }
void goto_lcd(int x, int y) {}
void put_string_lcd(char v[16]) { }
void print() { }
void delay() { }
/**************************************************************************/
/******************************** MAIN ***********************************/
void main()
{
long sy;
float s,f,p,n,m;
char v[16];
sy=0;
*0x9F &= 0xEF; // CLEAR ADFM BIT
mmc_init();
lcd_direction(0x00);
lcd_command(0x00);
set_tris_d(0x00);
setup_adc_ports( all_analog );
setup_adc(ADC_CLOCK_DIV_2); // i should change it to ADC_CLOCK_DIV_16
//start deflate
start:
set_adc_channel(0);
delay_us(10);
s=read_adc();
if (s>25){
output_high(pin_d3);
output_low(pin_d2);
goto start;}
output_low(pin_d3);
delay_ms(100);
print();
delay_ms(3000);
//inflate state
init_lcd();
goto_lcd(0,1);
sprintf(v,"pressure=");
put_string_lcd(v);
inflate:
set_adc_channel(0);
delay_us(10);
f=read_adc();
n=(f*5)/256;
p=(n*9375)/206;
goto_lcd(9,1);
sprintf(v,"%fummHg",p);
put_string_lcd(v);
if (f<178){
output_high(pin_d2);
goto inflate;}
output_low(pin_d2);
//deflate state
deflate:
set_adc_channel(1);
delay_us(10);
s=read_adc();
output_high(pin_d3);
delay_ms(100);
output_low(pin_d3);
delay_ms(100);
if (s>205){
sy++;}
if (sy<4){
goto deflate;}
set_adc_channel(0);
delay_us(10);
f=read_adc();
n=(f*5)/256;
p=(n*9375)/206;
mmc_write_block(1);
init_lcd();
goto_lcd(0,1);
sprintf(v,"Sys pres =");
put_string_lcd(v);
goto_lcd(0,2);
sprintf(v,"%fummHg",p);
put_string_lcd(v);
delay_ms(100);
//diastole
diastole:
output_high(pin_d3);
delay_ms(100);
output_low(pin_d3);
delay_ms(100);
set_adc_channel(1);
delay_us(10);
s=read_adc();
if (s>128)
{delay();
goto diastole;}
set_adc_channel(0);
delay_us(10);
f=read_adc();
n=(f*5)/256;
m=(n*9375)/206;
mmc_write_block(10);
init_lcd();
goto_lcd(0,1);
sprintf(v,"Diast pres =");
put_string_lcd(v);
set_adc_channel(0);
goto_lcd(0,2);
sprintf(v,"%fummHg",m);
put_string_lcd(v);
end:
set_adc_channel(0);
delay_us(10);
s=read_adc();
if (s>25)
{output_high(pin_d3);
goto end;}
output_low(pin_d3);}
Clears unused SFR 0x9F.4 rather than ADFM 0x9F.7i cleared the ADFM bit by putting this statement *0x9F &= 0xEF
Clears unused SFR 0x9F.4 rather than ADFM 0x9F.7
You are apparently using CCS C and it's built-in f7znction read_adc(). The compiler is expecting that the ADC is setup with the respective initialization functions. If you don't use it, you need to find out which ADC settings are made by default and which have to be done by direct register accesses. In case of doubt, you should inspect the generated code.
You'll find out that ADFM is cleared in CCS C unless you specify #device ADC=10 and use setup_adc().
In other words, this is a CCS specific rather than a general PIC16 related question.
Here are my answers to each question:
- The ADFM is cleared by default, so the (lazy) author may not have bothered setting this particular bit.
- Im not exactly sure about that statement. Looks like FvM above gave the correct one. Im not familiar with CCS C anymore, though i used it a few times 6-7 years ago but I ditched it in favor of Hi-Tech C.
- Absolutely no need to connect the VDD and GND to VREF+ and VREF- pins, respectively. That's a bad circuit.
- ADC_DIV_16 is correct since you get a Tad = 2us, which is more than the 1.6us minimum.
- Time delay should be greater than 19.8us, so obviously 10us is wrong.
Apparently. My basic approach is: If you are using CCS built-in functions, use them completely unless you are aware of a bug needing a workaround. But in the latter case, you'll have already checked what each function call does (or should do when working correctly) and you can easily supplement the missing SFR actions.i don't need to add #device ADC=8 because it's the default ,right?
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?