⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lm70.c

📁 基于ATMEL的ATMEGA8单片机对lm70--数字温度传感器芯片的DRIVER编程。
💻 C
字号:
/***********************************************
****       AVR  SPI接口使用范例   	          ***
****  	                                     ***
**** 作者:                                 ***
**** 编译器:WINAVR20050214                 ***
****外部晶振 4MHz,F_CPU=4000000             ***
***********************************************/
#include <avr/io.h>
#include "main.h"
void delay_us(uchar t)
{
  uchar time;
  for(time=0;time<5*t;time++);	   
}

//初始化SPI接口
void init_SPI(void)
{
    SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);		
    // 使能SPI接口,主机模式0 ,MSB位在先,模式0,16分频,SPI时钟约250KHz
}

void SPI_Write(uchar Wdata)
{
   SPDR=Wdata;
   while(!(SPSR&(1<<SPIF)));
}

/*-----------------------------------------------------------------------
Single_SPI    : 使用SPI接口写数据到device
 
输入参数:	cmd:	命令选择;
返回值		
   (SPI的收发是同时进行的)
-----------------------------------------------------------------------*/
void Single_SPI_Write(uint cmd)
{
	uchar ls;
    EnDevice;				 // 使能
    delay_us(10);
	
    SPDR = 0x0;			 	 // 传送命令到SPI寄存器
    while(!(SPSR&(1<<SPIF)));
	ls=SPDR;	     // 读取数据
	
	delay_us(10);
	
    SPDR = 0x00ff&cmd;		 // 传送命令到SPI寄存器
    while(!(SPSR&(1<<SPIF))); 	
    ls=SPDR;// 读取数据  
	delay_us(10);

    SPDR = 0x0;			
    while(!(SPSR&(1<<SPIF)));  
	ls=SPDR;
	delay_us(10);
    SPDR = 0x00ff&cmd;	  
    while(!(SPSR&(1<<SPIF)));  
	ls=SPDR;
	
	delay_us(5);/**/
    DisDevice;				 // 关断SPI通讯
    delay_us(10);

}

uint Single_SPI_Read(void)
{
	uint temperature=0;

    EnDevice;				 // 使能
    delay_us(10);
	
    SPDR = 0x0;			 	 // 传送
    while(!(SPSR&(1<<SPIF)));
	temperature=SPDR;	     // 读取数据
	
	delay_us(10);
    SPDR = 0x0;		         //传送
    while(!(SPSR&(1<<SPIF)));  
	
    temperature=(temperature<<8)|SPDR;// 读取数据  
	delay_us(2);
    DisDevice;				 // 关断SPI通讯
    delay_us(10);
	
    return temperature;

}

//decode 4bits data
void DecodeBCD(uint temp)
{
   unsigned char num_bit[5];

   //num_bit[4]=temp/10000;
   //temp=temp%10000;
   
   num_bit[3]=temp/1000;
   temp=temp%1000;

   num_bit[2]=temp/100;
   temp=temp%100;

   num_bit[1]=temp/10;
   
   num_bit[0]=temp%10; 
    
  /**********将转换结果发送到串行口***********/
  //putchar(48+num_bit[4]);	
  putchar(48+num_bit[3]);   	
  putchar(48+num_bit[2]);	
  putchar(48+num_bit[1]);	 
  putchar(48+num_bit[0]);
}

//将整型数按16 进制数拆分,送串口显示
void DecodetoHexBits(uint hex16)
{
   uchar n;
   uchar bit[4];
   uint temp;
   bit[3]=hex16&0x000f;
   temp=hex16>>4;
   bit[2]=temp&0x000f;
   temp=hex16>>8;
   bit[1]=temp&0x000f;
   temp=hex16>>12;
   bit[0]=temp&0x000f;

   //send to uart:
   putchar('0');	 
   putchar('x');
   
   for(n=0;n<4;n++){
      if(bit[n]<10)   putchar(48+bit[n]);	
      else putchar(55+bit[n]);
   } 
   
   putchar(0x0d);putchar(0x0a);//回车换行
}

//处理温度值,送串口显示
void Temperature_count(uint temp)
{
   float result_float;//温度的小数部分
   uchar result_int;  //温度的整数部分

   if((temp&0x8000)==0){//温度为正数
		temp = (temp>>5)&0x03ff;//
		result_int=(uchar)(temp*0.25);
		result_float=temp*0.25-result_int;
		//send conversion result to uart:
		putchar('+');	 
		DecodeBCD(result_int);//输出4位整数
		putchar('.');
		DecodeBCD(result_float*10000);//输出4位小数
		puts("℃");				
   }
   else{//温度为负数
		temp = temp>>5;//
		temp = 0xffff-temp+1;//求补
		temp &= 0x03ff;    //屏蔽高7位无效的数据
		result_int=(uchar)(temp*0.25);
		result_float=temp*0.25-result_int;
		//send conversion result to uart:
		putchar('-');	 
		DecodeBCD(result_int);//输出4为整数
		putchar('.');
		DecodeBCD(result_float*10000);//输出4位小数 
		puts("℃");				 
   }
}

int main(void)
{
    uint temp_result=0;
	uchar cmd;
    //上电默认DDRx=0x00,PORTx=0x00 输入,无上拉电阻
    //PORTA=0xFF;	//不用的管脚使能内部上拉电阻
    PORTC=0xFF;
    PORTD=0xFF;
    DDRD=(1<<PIN_TXD);	//串口的输出
    PORTB=~((1<<SPI_MOSI)|(1<<SPI_MISO)|(1<<SPI_SCK));							
    DDRB =(1<<SPI_CE)|(1<<SPI_SCK)|(1<<SPI_MOSI);//设定SPI接口
    									
    init_USART();
    init_SPI();

    puts("Pls Input Char!");
	puts("Input Char 'd' to Read Device ID!");
    puts("Input Any other Char to Read Temperature!");
    while(1)
	{
	    cmd=getchar();
	    delay(250);delay(250);

	    if(cmd=='d'){
		    puts("Device ID Is:");
			Single_SPI_Write(0xff);//
			delay(250);
			temp_result=Single_SPI_Read();//
			DecodetoHexBits(temp_result);
			putchar(0x0d);putchar(0x0a);//回车换行
		}
		else{
		    puts("Temperature Is:");
			Single_SPI_Write(0x0);//
			delay(250);
			temp_result=Single_SPI_Read();//
			DecodetoHexBits(temp_result);
			Temperature_count(temp_result);			
			putchar(0x0d);putchar(0x0a);//回车换行
		
		}
	}
       return 1;
}







/*
串行外设接口-SPI
    SPI接口可以令ATmega16 和外设或其他AVR器件进行高速的同步数据传输
	ATmega16的SPI接口同时还用来实现程序和EEPROM的下载和上载。请参见[SPI串行编程和校验]。
	
	SPI系统包括两个移位寄存器和一个主机时钟发生器。
	主机和从机将需要发送的数据放入相应的移位寄存器。
	主机在SCK 引脚上产生时钟脉冲以交换数据。
	主机的数据从主机的MOSI 移出,从从机的MOSI 移入;从机的数据从从机的MISO 移出,从主机的MISO 移入
	(其实就是由主机和从机构成一个16位的循环移位寄存器,所以收发数据是同时的,收发函数可以写成一条函数)

	SPI系统的发送方向只有一个缓冲器,而在接收方向有两个缓冲器。
	也就是说,在发送时一定要等到移位过程全部结束后才能对SPI 数据寄存器执行写操作。
	而在接收数据时,需要在下一个字符移位过程结束之前通过访问SPI 数据寄存器读取当前接收到的字符。
	否则第一个字节将丢失。
	
SS引脚的功能
	1从机模式
	从机模式当SPI配置为从机时,从机选择引脚SS总是为输入。
	SS 为低将激活SPI 接口, MISO成为输出( 用户必须进行相应的端口配置) 引脚,其他引脚成为输入引脚。
	当SS 为高时所有的引脚成为输入, SPI 逻辑复位,不再接收数据。
	SS引脚对于数据包/字节的同步非常有用,可以使从机的位计数器与主机的时钟发生器同步。
	当SS 拉高时SPI从机立即复位接收和发送逻辑,并丢弃移位寄存器里不完整的数据。
	
	2主机模式
	当SPI 配置为主机时(MSTR 的SPCR 置位),用户可以决定SS 引脚的方向。
	若SS 配置为输出,则此引脚可以用作普通的I/O 口而不影响SPI 系统。典型应用是用来驱动从机的SS 引脚。
	(单主机系统,SS引脚最好设成输出)
	
	如果SS 配置为输入,必须保持为高以保证SPI 的正常工作。
	若系统配置为主机, SS 为输入,但被外设拉低,则SPI 系统会将此低电平解释为有一个外部主机将自己选择为从机。
	为了防止总线冲突, SPI 系统将实现如下动作:
	1. 清零SPCR 的MSTR 位,使SPI 成为从机,从而MOSI 和SCK 变为输入。
	2. SPSR 的SPIF 置位。若SPI 中断和全局中断开放,则中断服务程序将得到执行。
	因此,使用中断方式处理SPI 主机的数据传输,并且存在SS 被拉低的可能性时,中断服务程序应该检查MSTR 是否为"1”。
	若被清零,用户必须将其置位,以重新使能SPI 主机模式。
	
数据模式(中文手册有点混乱,请参考英文原版)
	相对于串行数据, SCK的相位和极性有4种组合,由CPHA和CPOL控制组合的方式。
	SPI模式 CPOL CPHA      起始沿      结束沿
	  0      0    0    采样(上升沿)   设置(下降沿)
	  1      0    1    设置(上升沿)   采样(下降沿)
	  2      1    0    采样(下降沿)   设置(上升沿)
	  3      1    1    设置(下降沿)   采样(上升沿)

SPI控制寄存器-SPCR
	Bit 7 – SPIE: 使能SPI 中断
		置位后,只要SPSR 寄存器的SPIF 和SREG 寄存器的全局中断使能位置位,就会引发SPI 中断。
	Bit 6 – SPE: 使能SPI
		SPE 置位将使能SPI。进行任何SPI 操作之前必须置位SPE。
	Bit 5 – DORD: 数据次序
		DORD 置位时数据的LSB 首先发送;否则数据的MSB 首先发送。
	Bit 4 – MSTR: 主/ 从选择
		MSTR置位时选择主机模式,否则为从机。
		如果MSTR为"1”,SS配置为输入,但被拉低,则MSTR 被清零,寄存器SPSR 的SPIF 置位。
		用户必须重新设置MSTR 进入主机模式
	Bit 3 – CPOL: 时钟极性
		CPOL 置位表示空闲时SCK 为高电平;否则空闲时SCK 为低电平。
	Bit 2 – CPHA: 时钟相位
		CPHA 决定数据是在SCK 的起始沿采样还是在SCK 的结束沿采样。
	Bits 1, 0 – SPR1, SPR0: SPI 时钟速率选择1 与0
		确定主机的SCK 速率。
		SPR1 和SPR0 对从机没有影响。
		SCK 和振荡器的时钟频率fosc关系如下表所示:
			SPI2X SPR1 SPR0 SCK 频率
			  0 	0 	0 	fosc/4
			  0 	0 	1 	fosc/16
			  0		1 	0 	fosc/64
			  0 	1 	1 	fosc/128
			  1 	0 	0 	fosc/2
			  1 	0 	1 	fosc/8
			  1 	1 	0 	fosc/32
			  1 	1 	1 	fosc/64
			  
SPI状态寄存器-SPSR
 	Bit 7 – SPIF: SPI 中断标志
		串行发送结束后,SPIF 置位。
		若此时寄存器SPCR 的SPIE 和全局中断使能位置位,SPI中断即产生。
		如果SPI 为主机, SS 配置为输入,且被拉低, SPIF 也将置位。
		进入中断服务程序后SPIF自动清零。
		或者可以通过先读SPSR,紧接着访问SPDR来对SPIF清零。
	Bit 6 – WCOL: 写碰撞标志
		在发送当中对SPI 数据寄存器SPDR写数据将置位WCOL。
		WCOL可以通过先读SPSR,紧接着访问SPDR 来清零。
	Bit 0 – SPI2X: SPI 倍速
		置位后SPI 的速度加倍。
		若为主机,则SCK 频率可达CPU 频率的一半。
		若为从机,只能保证fosc /4。
		
SPI数据寄存器-SPDR
	SPI数据寄存器为读/写寄存器,用来在寄存器文件和SPI移位寄存器之间传输数据。
	写寄存器将启动数据传输,
	读寄存器将读取寄存器的接收缓冲器。
*/


⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -