?? spi.c
字號:
/*********************************************************************************************************
** SPI 驅動程序
** (c) Copyright 2006-2008, limaokui
** All Rights Reserved
**
** V1.0.0
**
**
**--------------文件信息--------------------------------------------------------------------------------
**文 件 名:SPI.c
**創 建 人: 李茂奎
**最后修改日期: 2006年9月2日
**描 述: SPI驅動程序
**
**--------------歷史版本信息----------------------------------------------------------------------------
** 創建人: 李茂奎
** 版 本: V1.00
** 日 期: 2006年9月2日
** 描 述: 原始版本
**
**------------------------------------------------------------------------------------------------------
** 修改人: 李茂奎
** 版 本:
** 日 期:
** 描 述:
**
**--------------當前版本修訂------------------------------------------------------------------------------
** 修改人: 李茂奎
** 日 期: 2006年9月2日
** 描 述:
**
**------------------------------------------------------------------------------------------------------
*********************************************************************************************************/
/*
ATmega128的SPI采用硬件方式實現面向字節的全雙工3線同步通信,
支持主機、從機和2種不同極性的SPI時序,通信速率有7種選擇,
主機方式的最高速率為1/2系統時鐘,從機方式最高速率為1/4系統時鐘。
AVR的SPI由一個16位的循環移位寄存器構成,當數據從主機方移出時,從機的數據同時也被移入,
因此SPI的發送和接收在一個中斷服務中完成。
在SPI中斷服務程序中,先從SPDR中讀一個接收的字節存入接收數據緩沖器中,再從發送數據緩沖
器取出一個字節寫入SPDR中,由SPI發送到從機。
數據一旦寫入SPDR,ISP硬件開始發送數據。
下一次ISP中斷時,表示發送完成,并同時收到一個數據。
SPI為硬件接口和傳輸完成中斷申請,所以使用SPI傳輸數據的有效方法是采用中斷方式+數據緩存器的設計方法。
在對SPI初始化時,應注意以下幾點:
.正確選擇和設置主機或從機,以及工作模式(極性),數據傳輸率;
.注意傳送字節的順序,是低位優先(LSB First)還是高位優先(MSB Frist);
.正確設置MOSI和MISO接口的輸入輸出方向,輸入引腳使用上拉電阻,可以節省總線上的吊高電阻。
*/
#include "config.h"
static uint8 Spi_Receive_Data[SPI_RECEIVE_DATA_BUFFER_SIZE];
static uint8 Spi_Send_Data[SPI_SEND_DATA_BUFFER_SIZE];
CirQueue Spi_Receive_Buffer={0,0,0,Spi_Receive_Data,SPI_RECEIVE_DATA_BUFFER_SIZE,0,0,0};
CirQueue Spi_Send_Buffer={0,0,0,Spi_Send_Data,SPI_SEND_DATA_BUFFER_SIZE,0,0,0};
#pragma interrupt_handler spi_stc_isr:iv_SPI_STC
void spi_stc_isr(void)
{
if(Spi_Receive_Buffer.status==SPI_DATA_RECEIVE)
EnQueue(&Spi_Receive_Buffer,SPDR); //從SPI口讀出收到的字節
if (Spi_Send_Buffer.status==SPI_DATA_SEND)
{
if(!EmptyQueue(&Spi_Send_Buffer))//如果發送緩沖區中有待發的數據
{
SPDR = DeQueue(&Spi_Send_Buffer); //發送一個字節數據,并調整指針
}
else
{
Spi_Send_Buffer.status=SPI_DATA_FREE;
}
}
}
uint8 Spi_Get_Char(void)
{
uint8 data;
while (EmptyQueue(&Spi_Receive_Buffer)); //無接收數據,等待
data = DeQueue(&Spi_Receive_Buffer); //從接收緩沖區取出一個SPI收到的數據
return data;
}
void Spi_Put_Char(uint8 c)
{
while (FullQueue(&Spi_Send_Buffer));//發送緩沖區滿,等待
if (Spi_Send_Buffer.count)//發送緩沖區已中有待發數據
{ //或SPI正在發送數據時
EnQueue(&Spi_Send_Buffer,c);//將數據放入發送緩沖區排隊
}
else
SPDR = c; //發送緩沖區中空且SPI口空閑,直接放入SPDR由SIP口發送
}
uint8 Spi_Receive(uint8 *buffer,uint16 length)
{
uint16 i;
Spi_Receive_Buffer.status=SPI_DATA_RECEIVE;
for(i=0;i<length;i++)
{
*buffer++=Spi_Get_Char();
}
Spi_Receive_Buffer.status=SPI_DATA_FREE;
return i;
}
uint8 Spi_Send(uint8 *buffer,uint16 length)
{
uint16 i;
Spi_Send_Buffer.status=SPI_DATA_SEND;
for(i=0;i<length;i++)
{
Spi_Put_Char(*buffer++);
}
Spi_Send_Buffer.status=SPI_DATA_FREE;
return i;
}
uint8 Spi_SendReceive(uint8 *buffer,uint16 sendlength,uint16 receivelength)
{
uint16 i;
uint8 *ptr;
ptr=buffer;
if (receivelength!=0)
{
Spi_Receive_Buffer.status=SPI_DATA_RECEIVE;
}
Spi_Send_Buffer.status=SPI_DATA_SEND;
for(i=0;i<sendlength;i++)
{
Spi_Put_Char(*ptr++);
}
ptr=buffer;
for(i=0;(i<receivelength)&&(i<sendlength);i++)
{
*ptr++=Spi_Get_Char();
}
Spi_Send_Buffer.status=SPI_DATA_FREE;
Spi_Receive_Buffer.status=SPI_DATA_FREE;
return i;
}
void Spi_Init(void)
{
uint8 temp;
#if (CPU_TYPE == M32)|| (CPU_TYPE == M16) // MISO-PB6,MOSI-PB5,SCK-PB7,SS-PB4
#define DDR_SPI DDRB
#define PORT_SPI PORTB
#define DD_MOSI 5
#define DD_MISO 6
#define DD_SCK 7
#define DD_SS 4
#endif
#if CPU_TYPE == M8 // MISO-PB6,MOSI-PB5,SCK-PB7,SS-PB4
#define DDR_SPI DDRB
#define PORT_SPI PORTB
#define DD_MOSI 3
#define DD_MISO 4
#define DD_SCK 5
#define DD_SS 2
#endif
#if (CPU_TYPE == M128)||(CPU_TYPE == M64 ) // MISO-PB6,MOSI-PB5,SCK-PB7,SS-PB4
#define DDR_SPI DDRB
#define PORT_SPI PORTB
#define DD_MOSI 2
#define DD_MISO 3
#define DD_SCK 1
#define DD_SS 0
#endif
DDR_SPI = DDR_SPI|(1<<DD_SS)|(1<<DD_MOSI)|(1<<DD_SCK); //MISO=input and MOSI,SCK,SS = output
PORTB |=(1<<DD_MISO)|(1<<DD_SS); //MISO上拉電阻有效
SPCR = (1<<SPIE)|(1<<SPE)|(1<<MSTR); //SPI允許,4X 主機模式,MSB先發,SPI模式0 (CPOL CPHA 00(0) 01(1) 10(2) 11(3))
// SPSR = 0;
SPSR = (1<<SPI2X); //enable spi2x
temp = SPSR;
temp = SPDR; //清空SPI,和中斷標志,使SPI空閑
}
/*
void main(void)
{
uint8 I;
CLI(); //關中斷
spi_init(); //初始化SPI接口
SEI(); //開中斷
while()
{
putSPIchat(i); //發送一個字節
i++;
Spi_Get_Char(); //接收一個字節(第一個字節為空字節)
}
}
*/
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -