51 模拟spi的程序

2009年07月10日 10:01    发布者:wangkj
#include "upsd.h"        
#define uchar unsigned char
#define uint unsigned int

#define WREN 0x06        // 写使能锁存指令
#define RDSR 0x05        // 读状态寄存器指令
#define WRSR 0x01        // 写状态寄存器指令
#define READ 0x03        // 读存储器阵列指令
#define WRITE 0x02        // 写存储器阵列指令
sbit _CS = P1^0;            // SPI总线的片选信号线
sbit SCK = P1^1;            // SPI总线的钟信号线
sbit SI = P1^2;            // SPI总线的串行数据输入线
sbit SO = P1^3;            // SPI总线的串行数据输出线
#define BUFFSIZE 16
uchar readbuff,writebuff;    // 读写缓冲区
/*从SPI总线上读入一个字节*/
uchar read(void)
{
    uchar data i,inData;
    for(i=0; i<8; i++)        // 移8次
    {   
        SCK = 0;        // 拉低时钟线
        inData <<= 1;   
        inData |= SO;    // 从SPI总线的数据输出线SO上读入一位
        SCK = 1;        // 拉高时钟线
    }
    return(inData);
}
/*输出一个字节到SPI总线上*/
void write(uchar outData)
{
    uchar data i;
    for(i=0; i<8; i++)        // 移8次
    {
        SCK = 0;   
        outData <<= 1;
        SI = CY;            // 移出一位,送出至SPI总线的数据输入线SI上
        SCK = 1;
    }
}/*读SPI器件的状态*/
uchar readSR(void)
{
    uchar data SR_Data;
    _CS = 0;                // 选中器件
    write(RDSR);            // 发送读状态寄存器指令
    SR_Data = read();        // 得状态值
    _CS = 1;                // 取消对器件的选定
    return(SR_Data);        // 送回状态值
}
/*写SPI器件的状态寄存器*/
void writeSR(uchar SR_Data) /*可以改变SPI器件看门狗时间,设定受保护阵列范围*/
{
    _CS = 0;
    write(WREN);         // 发送使能锁存指令
    _CS = 1;
    _CS = 0;
    write(WRSR);         // 发送写状态寄存器指令
    write(SR_Data);        // 写入状态值
    _CS = 1;     
}
/*将一串数据写入指定的EEPROM阵列地址*/
void writeEEPROM(uint addr,len)
{
    uchar data i,com;
    _CS = 0;
    write(WREN);         //发送使能锁存指令
    _CS = 1;
    _CS = 0;
    com = (addr>>8) & 0x08 | WRITE;    DPL = addr;
    write(com);            // 发送读命令和目标地址的最高位A8
    write(DPL);            // 发送地址的低8位
    for(i=0; i     _CS=1;
   
}
/*从指定的EEPROM阵列地址读出一串数据*/
void readEEPROM(uint addr,len)
{
    uchar data i,com;   
    _CS = 0;
    com = (addr>>8) & 0x08 | READ;    DPL = addr;
    write(com);        // 发送读命令和目标地址的最高位A8
    write(DPL);        // 发送地址的低8位
    for(i=0; i     _CS = 1;
}
//**************************************************************************************************
xdata uchar    CONTROL_B _at_ 0x803;
xdata uchar    DATAOUT_B _at_ 0x805;
xdata uchar    DIRECTION_B    _at_ 0x807;
uchar position;        // LED的位码存储单元
uchar a;            // 8字节长显示缓冲区
uchar *disp_ptr;        // 显示缓冲区的指针
uchar code led_code = {0x03,0x9f,0x25,0x0d,0x99,0x49,0x41,0x1f,0x01,0x09,0xff};   
//数字码表0-9,LED无显示时对应码值为0xff
/********LED显示的初始化********/
void led_init(void)            
{
    CONTROL_B = 0;            
    DATAOUT_B = 0;            
    DIRECTION_B = 0xff;        
    position = 0x80;        
    disp_ptr = &a;            
}
/*1位LED显示,并更新位码和显示缓冲指针*/   
void display(void)            
{   
    P4 = 0xff;               
    DATAOUT_B = position;            
    position = position>>1;            
    if(position == 0) position = 0x80;
    P4 = led_code[*disp_ptr++];        
    if(position == 0x80) disp_ptr = &a;        
}
/*将一个无符号型整数的每位数据分别装载到显示缓冲区*/
void loadbuff(uint sum)
{
    a = sum/10000;    a = (sum%10000)/1000;
    a = (sum%1000)/100;    a = (sum%100)/10;
    a = sum%10;    a = 10; a = 10;a = 10;
}
//***************************************************************************************
#define TIMER0_COUNT 0xf8CD
            // TH0=0xf8,TL0=0xcd,在11.0592MHz的晶振频率下,可实现2ms的计数
bit timer0int;        // 2ms定时的标志位
/**********初始化定时器0**********/
void timer0_init(void)        
{
    TMOD &= 0xf0;
    TMOD |= 0x01;            
    TL0 = (TIMER0_COUNT & 0x00ff);   
    TH0 = (TIMER0_COUNT >> 8);   
    PT0 = 0;            
    ET0 = 1;               
    TR0 = 1;            
    timer0int = 0;            
}
/*定时器0的中断服务程序,每次中断置中断标志位*/
void timer0isr(void) interrupt 1                        
{   
    TL0 = TL0 + (TIMER0_COUNT & 0x00FF);   
    TH0 = TH0 + (TIMER0_COUNT >> 8);   
     timer0int = 1;            
}
//***************************************************
bit okflag;            // 外部脉冲计数加一标志
void int0_init(void)
{
    IT0 = 1;            // 边沿触发
     EX0 = 1;
    EA  = 1;            // 允许所有中断源
    okflag = 0;
}   
void int0isr(void) interrupt 0     
{
     okflag = 1;
}   
//***********************************************************************
main()
{   
    uchar i = 0;uint sum;   
    WDKEY = 0x55;    // 关看门狗定时器
    writeSR(0x10);    // 初始化X5043的状态寄存器
    while((readSR()&0x01) == 1);    // 等待X5043的非易失性写完成
    readEEPROM(0x00,2);        // 读入0x00和x01两个单元的内容
    if((readbuff == 0x55) && (readbuff == 0xaa))
    {    // 如果分别为0x55和0xaa,说明已经初始化过该芯片
        readEEPROM(0x02,2);        // 读出0x02和0x03两个单元的内容
        sum = ((uint)readbuff<<8)+readbuff;
            // 根据0x02和0x03两个单元的内容初始化计数值
    }
    else
    {        // 否则对芯片进行初始化
        sum=0;    // 初始化计数值为0
        writebuff=0x55;writebuff=0xaa;        //设定初始化标记为0x55,0xaa
        writebuff=0;writebuff=0;        // 初始化0x02和0x03两个单元的内容
        writeEEPROM(0x00,4);         // 写入初始化的设定字符串
    }
    loadbuff(sum);   
    led_init();   
    timer0_init();   
    int0_init();
    for(;;)
    {
        if(timer0int)
        {
            timer0int=0;
            display();        // 每2ms显示一位LED
            if(okflag)            // 如果脉冲计数值加一
            {
                if((readSR()&0x01)!=1)    // X5043可写
                {
                    okflag=0;         // 清除okflag标志
                    sum++;            // 计数加一   
                    writebuff=sum>>8;    writebuff=sum;   
                    writeEEPROM(0x02,2);        // 发送新的计数值
                    loadbuff(sum);        // 装载显示缓冲
                }
            }   
        }
    }
}
该文章有附件资料,如需下载请访问 电脑版

网友评论

wangkj 2009年07月10日
源码 rar文件。
node 2009年07月10日
顶老王
Netjob 2009年07月10日
路过~,顶一下。
诸葛孔明 2009年07月10日
顶上,楼主辛苦
wangkj 2009年07月10日
这个是俺搜出来的,写的最规范的。非原创。
老郭 2009年07月10日
1489
lelee007 2009年07月12日
顽强地路过,并顶之;P
jeff 2010年07月02日
好咚咚
wangkj 2010年07月02日
我靠,挖坟啊。
不过,这个问题,很多人多次问过。
tkggwxfss 2010年07月11日
谢谢啦
wangkj 2010年07月12日
:)
kevin_chan 2010年07月12日
谢谢,受用了
ksf1006 2010年07月20日
顶起来!!
solo_74 2010年08月17日
看看,学习下!:)
wxw123321 2010年09月06日
顶起
fymbl 2010年09月22日
学习一下。
lising 2010年09月26日
不错!顶
marjolein 2010年10月11日
thanks
dalfer 2010年10月14日
模拟的SPI让我头疼,显示接口的SPI操作不关定时器中断就不行,不然会显示乱码,没办法!
sdlyyy 2011年03月05日
非常感谢,好好学习。
onlylord 2011年07月06日
谢谢分享
wfnic 2011年07月10日
hao1h
wlp267 2011年07月13日
不错!顶
xzz88 2011年07月25日
我需要一个~
xzz88 2011年07月25日
我的分,怎么这么少了呢?
phil_guo 2011年09月14日
:victory:
ltt198511 2011年10月27日
下来看看啊
linkai_joseph 2011年12月27日
xiexielouzhule
guochangfei20 2012年02月15日
不错不错,学习了。。。
此人较为厉害 2013年06月13日
好东西,谢谢了