MAX6675 SPI
-
- Posts: 6
- Joined: 20 Oct 2007 12:01
MAX6675 SPI
Hi, can anybody help me with code to init and read data from a MAX6675?
Re: MAX6675 SPI
There is this post in the Basic forum, but it should give you a great starting point;
http://www.mikroe.com/forum/viewtopic.p ... ht=max6675
http://www.mikroe.com/forum/viewtopic.p ... ht=max6675
Tiens Zietsman wrote:Hi, can anybody help me with code to init and read data from a MAX6675?
[size=109][color=Red][b]Error[/b]: {Panic!} when trying to load: [reality shell]. kernel: "universe has been halted"...[/color][/size]
[url=http://www.bacardiware.com]Information Underground[/url]
[url=http://www.bacardiware.com]Information Underground[/url]
-
- Posts: 100
- Joined: 10 Nov 2005 16:37
- Location: APAC
I don't have the doc or compiler handy to verify with so check it for reality...
Wire it up as SPI. If the PIC you are using doesn't support SPI, you can use soft SPI or bit-bang it yourself. The CS select pin should be held HIGH ( setbit(port, pin) ) when you are not talking to the chip and brought LOW when you want to talk to the chip ( clearbit(port, pin) ). You can tie the pin to ground through a resistor and forget about setting CS through software if it is the only device on the bus and you don't care about the odd bit of noise getting to the MAX. Also, have a healthy ground plane and mount the chip so it matches the ambient temp as best as possible--vertical mounting stops the mounting board from trapping or peeling heat too much.
The MAX6675 returns a 16-bit word, so you will need to do two SPI reads and assemble them into a word. You could do this using absolute addressing, pointer, or shifting. I like absolute addressing, but the example below uses shifting:
The doc has the data fields, but I believe it is (MSB first):
15 -- always zero
14-5 -- integer value of temp in C
4-3 -- fractional value of temp in C (00=.0, 01=.25, 10=.5 and 11=.75)
2 -- normally low for a closed thermocouple
1 -- device ID (ha!), returns zero
0 -- ??, normally zero
So, basically you want to make sure bits 15,2,1 and 0 are zero under normal use and you want bits 14-5 for the integer value of the temp in C degrees.
Quick and dirty using shifting:
If you are doing your own SPI bit bang, you can just load a word value directly, or individual variables for the flag and values.
I'll test and repost if there are errors when I am back in the office.
cheers - CH
Wire it up as SPI. If the PIC you are using doesn't support SPI, you can use soft SPI or bit-bang it yourself. The CS select pin should be held HIGH ( setbit(port, pin) ) when you are not talking to the chip and brought LOW when you want to talk to the chip ( clearbit(port, pin) ). You can tie the pin to ground through a resistor and forget about setting CS through software if it is the only device on the bus and you don't care about the odd bit of noise getting to the MAX. Also, have a healthy ground plane and mount the chip so it matches the ambient temp as best as possible--vertical mounting stops the mounting board from trapping or peeling heat too much.
The MAX6675 returns a 16-bit word, so you will need to do two SPI reads and assemble them into a word. You could do this using absolute addressing, pointer, or shifting. I like absolute addressing, but the example below uses shifting:
The doc has the data fields, but I believe it is (MSB first):
15 -- always zero
14-5 -- integer value of temp in C
4-3 -- fractional value of temp in C (00=.0, 01=.25, 10=.5 and 11=.75)
2 -- normally low for a closed thermocouple
1 -- device ID (ha!), returns zero
0 -- ??, normally zero
So, basically you want to make sure bits 15,2,1 and 0 are zero under normal use and you want bits 14-5 for the integer value of the temp in C degrees.
Quick and dirty using shifting:
Code: Select all
Var TempHibyte, TempLowByte : byte;
TempWord : word;
Begin
// Do whatever Chip, TRIS, and safey setup you need and set CS pin high
// setup SPI hardware -- not for soft init
SPI_Init();
{ ---
Read the high byte and then low byte of the temp register, passing $00 since you need to send something. First bring CS low on whatever port and pin it resides.
-- }
ClearBit(PORT,PIN);
NOP;NOP; // delay just in case
TempHiByte := SPI_Read($00);
TempLowByte := SPI_Read($00);
SetBit(PORT,PIN);
// Make a word by shifting the hi byte into the upper 8 bits
// and ORing the low byte into the lower 8 bits of the word
TempWord := (TempHiByte SHL 8) OR TempLowByte;
// check to see if the MAX was read correctly.
// bits 15,2,1,0 should be zero, so mask and see
if (TempWord AND %1000000000000111) = 0 then begin // looks good
// if you don't care about the fractional temp, just shift off
// the lower status and fractional bits to get the temp
TempWord := TempWord SHR 5;
// if you want the fraction, pull it out of TempLowByte--less work,
// it is a byte. Without shifting, LoByte AND %00011000 will give
// the fractional temp as (00=00, 8=.25, 16=.50, 24=.75)
end // was a good read
else begin // wasn't a good read block here
// report the read was bad in this block, maybe snooze a few MS and try again, etc
end // wasn't a good read
End.
I'll test and repost if there are errors when I am back in the office.
cheers - CH
-
- Posts: 35
- Joined: 08 Feb 2007 11:25
Hi.
Here is my own SPI read function (in Basic) for the MAX6675. This can be on any Port Pins so frees up the internal SPI which I used for Comms to anothe PIC.
[code]
'******************************************************************************
' Get temperature From Max6675 via SPI 0 - 1024 Degrees
'******************************************************************************
sub function Read_Max6675() as Integer
' 12 bits Data = 4096 = 1024 Degrees
' 1 bit = 0.25 degree
TC_data = 0
TC_CS = 0 ' Chip Select
For ClockCount = 0 to 15 ' count off 16 clock cycles
TC_SCK = 1
TC_data = TC_data or TC_SDO ' Read Port Pin into LSB of TC_Data
If ClockCount < 15 then ' Stop after 15
TC_data = TC_data << 1 ' shift data to left to clear lsb for next bit
End If
TC_SCK = 0
Next ClockCount
TC_CS = 1
If TC_data.2 = 1 then
Result = 0
Else ' Open Circuit Thermocouple
'Result = (TC_data >> 3)
Result = TC_data >> 5 'Remove Decimal
End If
End sub
[/code]
It should be easy to convert into Pascal...Hope this Helps
Richard.
Here is my own SPI read function (in Basic) for the MAX6675. This can be on any Port Pins so frees up the internal SPI which I used for Comms to anothe PIC.
[code]
'******************************************************************************
' Get temperature From Max6675 via SPI 0 - 1024 Degrees
'******************************************************************************
sub function Read_Max6675() as Integer
' 12 bits Data = 4096 = 1024 Degrees
' 1 bit = 0.25 degree
TC_data = 0
TC_CS = 0 ' Chip Select
For ClockCount = 0 to 15 ' count off 16 clock cycles
TC_SCK = 1
TC_data = TC_data or TC_SDO ' Read Port Pin into LSB of TC_Data
If ClockCount < 15 then ' Stop after 15
TC_data = TC_data << 1 ' shift data to left to clear lsb for next bit
End If
TC_SCK = 0
Next ClockCount
TC_CS = 1
If TC_data.2 = 1 then
Result = 0
Else ' Open Circuit Thermocouple
'Result = (TC_data >> 3)
Result = TC_data >> 5 'Remove Decimal
End If
End sub
[/code]
It should be easy to convert into Pascal...Hope this Helps
Richard.
-
- Posts: 6
- Joined: 20 Oct 2007 12:01
MAX6675 SPI
I'm a total beginner. Needs spoon feeding for now.
I'm using an EASYPIC3 board with a PIC16F877A
I'm using PORTC for the SPI. RC1 to CS, RC3 to SCK and RC4 to SO.
My code looks like this:
program TempController;
var i,j,k : byte;
begin
k := 0;
TRISB := 0; // PORTB is output
TRISD:=0; // PORTD is output
SPI_init;
PORTC := PORTC and $FD; // select max6675
Delay_ms(100);
i := SPI_read(k);
j := SPI_read(k);
PORTC := PORTC or 2; // deselect max6675
PORTB := i; // To show what came in
PORTD := j; // on the LED's
end.
(this is my complete listing)
This doesn't work.
I think I initialised the PIC wrong/incomplete.
Do i need to set up PORTC or does SPI_Init do it automatically?
I'm using an EASYPIC3 board with a PIC16F877A
I'm using PORTC for the SPI. RC1 to CS, RC3 to SCK and RC4 to SO.
My code looks like this:
program TempController;
var i,j,k : byte;
begin
k := 0;
TRISB := 0; // PORTB is output
TRISD:=0; // PORTD is output
SPI_init;
PORTC := PORTC and $FD; // select max6675
Delay_ms(100);
i := SPI_read(k);
j := SPI_read(k);
PORTC := PORTC or 2; // deselect max6675
PORTB := i; // To show what came in
PORTD := j; // on the LED's
end.
(this is my complete listing)
This doesn't work.
I think I initialised the PIC wrong/incomplete.
Do i need to set up PORTC or does SPI_Init do it automatically?
Re: MAX6675 SPI
On your question, you need to tell use what device, depending on the needs you may need to use procedure
**Default settings with Spi_init() are: Master mode, clock Fosc/4, clock idle state low, data transmitted on low to high edge, and input data sampled at the middle of interval.
You can format the code like below/above;
Looking at your post the issue was you needed to highlight the text block what with you want to appear as formated text, then click the code button. Just a pointer it's super prising how much easier it is to read formated text.
-BaC
Code: Select all
Spi_Init_Advanced(master, data_sample, clock_idle, transmit_edge : byte);
**Default settings with Spi_init() are: Master mode, clock Fosc/4, clock idle state low, data transmitted on low to high edge, and input data sampled at the middle of interval.
You can format the code like below/above;
Looking at your post the issue was you needed to highlight the text block what with you want to appear as formated text, then click the code button. Just a pointer it's super prising how much easier it is to read formated text.
-BaC
Tiens Zietsman wrote:I'm a total beginner. Needs spoon feeding for now.
I'm using an EASYPIC3 board with a PIC16F877A
I'm using PORTC for the SPI. RC1 to CS, RC3 to SCK and RC4 to SO.
My code looks like this:
(this is my complete listing)Code: Select all
program TempController; var i,j,k : byte; begin k := 0; TRISB := 0; // PORTB is output TRISD:=0; // PORTD is output SPI_init; PORTC := PORTC and $FD; // select max6675 Delay_ms(100); i := SPI_read(k); j := SPI_read(k); PORTC := PORTC or 2; // deselect max6675 PORTB := i; // To show what came in PORTD := j; // on the LED's end.
This doesn't work.
I think I initialised the PIC wrong/incomplete.
Do i need to set up PORTC or does SPI_Init do it automatically?
[size=109][color=Red][b]Error[/b]: {Panic!} when trying to load: [reality shell]. kernel: "universe has been halted"...[/color][/size]
[url=http://www.bacardiware.com]Information Underground[/url]
[url=http://www.bacardiware.com]Information Underground[/url]
-
- Posts: 100
- Joined: 10 Nov 2005 16:37
- Location: APAC
The MAX6675 will work with the default SPI, saving some setup hassles. Always a good thing to check though.
You are on the right track. You need to set some config parameters and clean up your CS--sample below. Make sure you turn off the watch dog timer in the fuse config (Project), too. I am assuming your oscillator type and speed are set to match the physical hardware.
Since you note you have the EP3 board, I assume you are using the onboard LEDs. If not, make sure there is a resistor in the path of the each LED to keep the current reasonable (330-2K depending on your LEDs and eyes). If you have the LCD or a serial cable, they are both very useful for debugging, too.
You are on the right track. You need to set some config parameters and clean up your CS--sample below. Make sure you turn off the watch dog timer in the fuse config (Project), too. I am assuming your oscillator type and speed are set to match the physical hardware.
Since you note you have the EP3 board, I assume you are using the onboard LEDs. If not, make sure there is a resistor in the path of the each LED to keep the current reasonable (330-2K depending on your LEDs and eyes). If you have the LCD or a serial cable, they are both very useful for debugging, too.
Code: Select all
Program TempController;
Var i,j : byte;
Begin
// Do some setup for digital only, all outputs out and low
// except CS, and turn pull-ups off in option_reg
// *** turn off the watch dog timer (WDT) in the fuse config too
OPTION_REG := %10000000;
// Kill analog on chip (I think this correct for 877A)
CMCON := $00; // safety
ADCON0 := $00; // safety
ADCON1 := $07; // actually kills analog
// Set Port Directions to all out and zero them, except CS
// You will no doubt adjust and pare these down later
TRISA := 0; // PORTA,B,C,D are outputs
TRISB := 0;
TRISC := 0;
TRISD := 0;
TRISE := 0; // Ports and PSP, safety
PORTA := 0; // low your outputs
PORTB := 0;
PORTC := %00000001; // Bring CS high here
PORTD := 0;
PORTE := 0;
// sets TRIS itself, so don't bother above. remember that
// PIC SDI <- SDO device
SPI_init();
// if you wrap from here to the end in a while (1) loop and add
// a delay, you can watch the leds change with temp.
// PORTC := PORTC and $FD; // select max6675
PORTC.1 := 0; // bring select line low
// or use ClearBit(PORTC,1)
Delay_ms(1); // not really needed, but doesn't hurt
i := SPI_read(0); // send junk
j := SPI_read(0);
PORTC.1 := 1; // bring high, deselect CS again
// or use SetBit(PORTC,1);
PORTB := i; // To show what came in
PORTD := j; // on the LED's
End.
-
- Posts: 100
- Joined: 10 Nov 2005 16:37
- Location: APAC
-
- Posts: 6
- Joined: 20 Oct 2007 12:01
MAX6675 SPI
Thank you very much. I got it going.
also: Your suggestion to use rs323 was news to me.
I'm now using rs323 to help with the debugging.
also: Your suggestion to use rs323 was news to me.
I'm now using rs323 to help with the debugging.