代码共享:AVR单片机SPI实例
本人的一个SPI的实例,通过SPI实现两机通讯,采用中断方式实现双全工通讯。
本例用两MEGA8515实现,连接为:
MISO----MISO
MOSI----MOSI
SCK ----SCK
/SS ----/SS
将要发送的数据加载到发送缓冲区的函数fill_tx_buffer
和从接收缓冲区读出数据的函数read_rx_buffer未给出,
根据各自需求请自己完成。
#define SPI_RX_BUFFER_SIZE 10
#define SPI_RX_BUFFER_MASK ( SPI_RX_BUFFER_SIZE - 1 )
#define SPI_TX_BUFFER_SIZE 10
#define SPI_TX_BUFFER_MASK ( SPI_TX_BUFFER_SIZE - 1 )
#define SET_SPI_MODE PORTB.4
#define SPI_MODE PINB.4
static unsigned char SPI_RxBuf;
static volatile unsigned char SPI_RxHead;
static unsigned char SPI_TxBuf;
static volatile unsigned char SPI_TxHead;
//******************************************
// SPI 中断服务程序
//******************************************
interrupt void spi_isr(void)
{
unsigned char data;
if(spi_m==0) //如果spi_m为0,表明是接收状态
{
data = SPDR; //读入接受到的数据
SPI_RxBuf = data; //将接收到的数据存入接收缓存区
if ( SPI_RxHead== SPI_RX_BUFFER_MASK ) //如果是接收帧的最后一个数据
{
SPI_RxHead = 0; //已接收数据还原
MSTR=1; //接收完成,将SPI设回主方式
spi_trans_com=1; //置接收完成标志
}
else
{
SPI_RxHead++; //已接收数据计数器加1
}
}
else //如果spi_m为1,表明是发送状态
{
if ( SPI_TxHead <= SPI_TX_BUFFER_MASK) //如果要发送的数据还未全部发完
{
SPDR = SPI_TxBuf; //从发送缓存区取数发送
SPI_TxHead++; //已发送数据计数器加1
}
else //如果要发送的数据已全部发完
{
SPI_TxHead=0; //已发送数据计数器还原
DDRB.4=0;
SET_SPI_MODE=1; //释放总线,以便接收方进入主发送。
spi_m=0;
spi_sending=0; //清空发送中标记
}
}
}
//******************************************
// SPI 初始化
//******************************************
void InitSPI(void)
{
SPCR=0x52;
SPI_RxHead = 0;
SPI_TxHead = 0;
}
//******************************************
//发送数据
//******************************************
void spi_send(void)
{
if(spi_sending==0) //发送中标记为0,表明spi发送空闲
{
fill_tx_buffer(); //调用fill_tx_buffer函数,将要发送的数据加载到发送缓冲区
while(PINB.4==0) //如果PINB.4为低,表明总线被接受方占用,等待直至接受方发送完成。
{;}
InitSPI(); //初始化spi为主方式
DDRB.4=1;
SET_SPI_MODE=0; //将PORTB.4拉低,强迫接收方进入从接收方式
spi_m=1; //置spi_m标志表明为发送状态
delay_us(10);
spi_sending=1; //置spi_sending标志表明发送进行中
SPDR=0xFF; //开始发送,接收方接收到的第一个数据为0xFF应忽略
SPIE=1; //开SPI中断,
SPI_TxHead = 0; //已发送数据计数器清0
}
}
void main(void)
{
...
while(1)
{
...
if(spi_trans_com==1) //如果接收完成标志为1,表明有所数据已接收
{
read_rx_buffer(); //调用read_rx_buffer函数,将接收到的数据从接收缓冲区读出
spi_trans_com=0;//读完清除接收完成标志
}
...
}
} 好贴,顶! 好贴,实用性很强,谢谢Paul 好帖...学习之中... 此代码为本人原创,如有改进请不吝指正。 顶
好贴
偶最近开始学C编程
学习中.... 楼主
有一个问题
我发数据是上升沿采样
收数据是下降沿采样
有没有什么好的方法啊
我发了一个字节后马上要接收
现在的问题是我用
while(!(SPSR&(1<<SPIF)))
;
return SPDR;
来收的话
时钟都看不到
-----此内容被wowo于2005-04-27,15:12:15编辑过 好! 求教:是不是要包含什么头文件呀 这个程序能用于X5045P这个器件吗 他头文件没贴上来, 搂主,有一个不是很理解:SPI为全双工,一边发一边收,在你的中断服务程序中
为什么有个spi_m标志,看到你的中断程序,好像是半双工的,在发的同时不能接受的,
不知我的理解对么? ???
本例用两MEGA8515实现,连接为:
MISO----MISO
MOSI----MOSI
SCK ----SCK
/SS ----/SS
???
应该是这样吧
MISO----MOSI
MOSI----MISO to lchsh:
MISO----MISO
MOSI----MOSI
SCK ----SCK
是正确的,一个做了主机,另一个一定只能做从机了----模式变换. 不错不错 谢谢! 顶,正合我意 不错,顶下 你的这段代码是否对主从机都适合,我的意思是主从机都可以用同的这段代码进行工作呢 应该是都合适的. 应该是所有 IC~ 都用这个程序吧
这个方法不错,不过有些地方还不太懂.
就是IC初始化时,SPI怎么设置?
我的理解是
/SS 为输入且上拉使能
SPCR=(1<<spie)|(1<<SPE)|(1<<MASTRE)
其他口通过程序设置和SPI自动配置吧?
那这一段//-------
void spi_send(void)
{
if(spi_sending==0) //发送中标记为0,表明spi发送空闲
{
fill_tx_buffer(); //调用fill_tx_buffer函数,将要发送的数据加载到发送缓冲区
while(PINB.4==0) //如果PINB.4为低,表明总线被接受方占用,等待直至接受方发送完成。
{;}
InitSPI(); //初始化spi为主方式
DDRB.4=1;
//---------------------
//这里要不要将MOSI,SCK设置为输出?按我的理解应该要...
//----------------------
SET_SPI_MODE=0; //将PORTB.4拉低,强迫接收方进入从接收方式
//----------------------
//这样的话,从机的SPIF会置位吧,(MEGA8的...) 那假如从机初始化是开着SPI中断的,就进入中断执
//程序,但和主机一个程序的话,那进入中断后,接收到错误数据(主机都未发送),应舍弃吧.
//----------------------
spi_m=1; //置spi_m标志表明为发送状态
delay_us(10);
spi_sending=1; //置spi_sending标志表明发送进行中
SPDR=0xFF; //开始发送,接收方接收到的第一个数据为0xFF应忽略
//(从机判断的正确数据从FF开始?)
SPIE=1; //开SPI中断,
SPI_TxHead = 0; //已发送数据计数器清0
}
}
目前只考虑了主对从,从不动作. 的情况,发生冲突还没细想...
那应该就是 主机发送2字节数据(FF+数据),从机中断能收到3字节(错误数据+FF+数据)
不知道这样理解正确否?
-----此内容被989898于2005-11-15,16:05:19编辑过 删贴再顶...
闲的人帮忙看下~ “//这里要不要将MOSI,SCK设置为输出?按我的理解应该要...”
不用设置,SPI初始化为主方式后MOSI,SCK自动变为输出。
“//这样的话,从机的SPIF会置位吧,(MEGA8的...) 那假如从机初始化是开着SPI中断的,就进入中断执
//程序,但和主机一个程序的话,那进入中断后,接收到错误数据(主机都未发送),应舍弃吧. ”
mega8没使过不清楚,但mega8515,mega16上用过没有这样的问题。 哦,可能. 器件不同,MEGA8主方式不自动配置为输出,由用户定义. 那个SPIF置位是有的,可能8515不会吧.
可能还有两个问题, 如下
void spi_send(void)
{
if(spi_sending==0) //发送中标记为0,表明spi发送空闲
{
fill_tx_buffer(); //调用fill_tx_buffer函数,将要发送的数据加载到发送缓冲区
while(PINB.4==0) //如果PINB.4为低,表明总线被接受方占用,等待直至接受方发送完成。
{;}
//-------------------------------------------
//假如两台机器同时使用这个发送子程序,且能同时到达这里,
//那么两台机器照接下来的程序运行,SS脚都会变成输出,无法触发中断
//且一直有SPI_SENDING标志,无法进行下一次发送来初始化~
//我想是不是要在置SPI_SENDING 标志后,判断100ms内连续为1
//则清零并初始化SS引脚为输入
//-------------------------------------------
InitSPI(); //初始化spi为主方式
DDRB.4=1;
SET_SPI_MODE=0; //将PORTB.4拉低,强迫接收方进入从接收方式
spi_m=1; //置spi_m标志表明为发送状态
delay_us(10);
//----------------------------------------
//这里的延迟是干嘛用的?本来以为是跳过 因拉低SS引脚强迫接收方进入从机方式
//而引起的中断 ,但看楼主这样说,又不是了,仅仅是延迟?
//----------------------------------------
spi_sending=1; //置spi_sending标志表明发送进行中
SPDR=0xFF; //开始发送,接收方接收到的第一个数据为0xFF应忽略
//(从机判断的正确数据从FF开始?)
SPIE=1; //开SPI中断,
SPI_TxHead = 0; //已发送数据计数器清0
}
} 还有:
interrupt void spi_isr(void)
{
unsigned char data;
if(spi_m==0) //如果spi_m为0,表明是接收状态
{
}
else //如果spi_m为1,表明是发送状态
{
//SPI_M,就是用来判是处于什么方式的吧,有没可能出现 SPI_M为1,
//但MSTR被拉低变成0的情况,那被拉低的从机没有清SPI_M标志的话,就进入了发送中断
//被拉低是为了接收中断的,与本意冲突~ “//-------------------------------------------
//假如两台机器同时使用这个发送子程序,且能同时到达这里,
//那么两台机器照接下来的程序运行,SS脚都会变成输出,无法触发中断
//且一直有SPI_SENDING标志,无法进行下一次发送来初始化~
//我想是不是要在置SPI_SENDING 标志后,判断100ms内连续为1
//则清零并初始化SS引脚为输入
//------------------------------------------- ”
完全有可能,但几率很小,至少到现在还未见影响(代码已用于产品上2年多了)。修正一下还是有必要。
“//----------------------------------------
//这里的延迟是干嘛用的?本来以为是跳过 因拉低SS引脚强迫接收方进入从机方式
//而引起的中断 ,但看楼主这样说,又不是了,仅仅是延迟?
//---------------------------------------- ”
延迟的作用是等待从机完成主到从地变换,毕竟要执行完这个过程是要点时间的。
“//SPI_M,就是用来判是处于什么方式的吧,有没可能出现 SPI_M为1,
//但MSTR被拉低变成0的情况,那被拉低的从机没有清SPI_M标志的话,就进入了发送中断
//被拉低是为了接收中断的,与本意冲突~ ”
这个不会,在进入主发送时有总线占用的判断,而在释放总线时SPI_M会被清除。 照楼主的思路基本上实现了,不过我两块板用了3根数据线和 2根电源线连着的。。。
这个电源线是不是可以省的,具体不会弄。。。 弄个电容+二极管什么的就可以了么。。。 很不错,谢谢你的实例!!!
我也正准备用这个
感觉IIC得太麻烦~~~中断里的一大串case吓人 问一个初级的问题~~
从机发送数据的时候,如果有别的中断占用了时间
假设用了10us,错过了向SPDR发送数据,这样是不是会造成通信故障? 中断是CPU的事.本次传送是SPI硬件的事情. 有无SPI/USI的例程???
TestCode-->看21ic里给你的鸡毛信... 我用SPI 与ZLG 7289 试了几天都没成功,呜呜........ 看了一些回复,感觉很无奈
我觉得楼主主要是想把自己的程序贴出来和大家共同研究
但是感觉好多人总是想怎么可以直接把这个东西拿来就用,== 我以前也用SPI的接口对另外的片子进行过程序烧写.比如用mega162来烧写和配置Tiny2313,mega48等.
接口的连线是跟楼主一样的. 不需要交叉,一一对应就好了!
大家在用别人的代码的时候多思考下,不要企图拿来就用,要分析下的嘛!
别人只是给你参考,不是给你答案!
同意bengol的看法! 楼主太厚道了,我正在为这个发愁呢,谢谢楼主,顶!!!! 这几天在搞SPI双机通讯(两片mega88),中断方式发送、中断方式接收通讯正常,查询方式发送,中断方式接收,通讯不正常,只收到一个数据 顶 测试的速度有多快? 先收藏了,慢慢看。 多谢 真好,多谢! 先收藏了~问个菜菜的问题,
DataSheet上的振荡器的时钟频率fosc指的是什么意思? 参考楼主的方法,做了个SPI多机通讯的试验,一个M128需要与一个M162通讯,同时还要能操作一块SD卡,连接上都没问题。 楼上成功了吗 没问题!成功了啊! 我正在用两个mega8做spi试验,两个单片机必须要设置成一个输入一个输出吗?sck,miso,mosi的输入输出需要人为设定I/O还是只需设置成spi格式就行了?新手,还请高人指导! 我用两个mega8通信仿真时,怎么两个芯片的频率一样的时候不行。但我调低了主机的频率又可以了。但从机发回数据时主机又不行了,我想是不是频率问题呢?还是仿真的时候不行,实物可以啊?请高手指教!!!!!!! 楼上的你好,我也在弄SPI M16与M8通信 有QQ吗 我的52115953,交流一下:) 好贴!顶 再顶 学习一下,我的下载都是通过串口实现的,有机会改用SPI试试。谢谢楼主共享,回去好好学习一下 学习一下,我的下载都是通过串口实现的,有机会改用SPI试试。谢谢楼主共享,回去好好学习一下 看一下,谢谢了 楼主这个程序,省得太多,为什么不把库和其他函数的定义写出来,
比如PINB.4这是什么?
DDRB.4
fill_tx_buffer();
spi_m是状态,具体怎么做的?
这些函数都没列出来,想研究研究都没有办法。
我没有意冒犯楼主,只是觉得这样判断不出这个程序到底怎么样。 楼主这个程序,省得太多,为什么不把库和其他函数的定义写出来,
比如PINB.4这是什么?
DDRB.4
fill_tx_buffer();
spi_m是状态,具体怎么做的?
这些函数都没列出来,想研究研究都没有办法。
我没有意冒犯楼主,只是觉得这样判断不出这个程序到底怎么样。 楼上的说的好呀,我顶! 严重支持 MISO上总是没有数据,这根线就可以不连了。 顶LZ个肺了,不错!!! 谢谢楼主分享!! 不错 这么老的东西还能翻出,佩服。
这个程序有一个问题:通讯中如有一方复位将导致以后一直出错,请使用时注意自行修改。怎么改应该很容易的,我就不说了。 SPI多机通信可以仿真调吗 如果一带几个机器呢?这样实现起来好像就不太容易!! //这样的话,从机的SPIF会置位吧,(MEGA8的...) 那假如从机初始化是开着SPI中断的,就进入中断执
//程序,但和主机一个程序的话,那进入中断后,接收到错误数据(主机都未发送),应舍弃吧.
【21楼】的这个问题还没有解决 随便请问一下,我做了一个双工程序,主机发送0x55,0x00 0x00,0x55,从机发送0xaa,0x00,0x00,0xaa;主机只能接收到0x00,0x00,0xaa;从机收到0x00,0x55,0x00,0x00,0x55,这可能是什么原因引起的呀??? 不错,好好学习~ SPI能做到全双工么? 只能是半双工啊 好!谢谢 学习中 很好,谢谢楼主! 收藏 好东西
谢谢分享 酷帖! 正要用SPI呢,没想到这么巧啊!^_^ 正要用SPI呢,没想到这么巧啊!^_^ 嘿嘿,来看看 学习! 学习中,正在学C 收藏,谢谢 ^_^ 谢谢,学习了 请教SPI怎么和93C66通讯? 初来论坛,支持下! jihao 看看也好! 做个记号! 先收藏了嘿嘿 看到此贴,很是欣喜,先收藏了,支持一下。
AVR新手上路,正在学习AVR单片机,我是边学习边搞仿真,学到SPI,自己编了一段程序,用Protus仿真,可它就是不干活,想请楼主指教一下?
你这段程序能在mega8上跑吧(我学的是mega8)?
自编程序:
主机程序:
/***************************************/
/* 设置为从机方式 */
/***************************************/
void SPI_SlaveInit(void)
{DDRD=0XFF;
DDRB=0XD3;
PORTB=0X2C;
SPCR=0X40;
}
char SPI_SlaveReceive(void)
{
while(!(SPSR & (1<<SPIF))) {;}/*Wait for reception complete*/
return SPDR; /*Return data register*/
}
/***************************************/
/* 主程序 */
/***************************************/
int main (void)
{char i;
SPI_SlaveInit();
while(1)
{i=SPI_SlaveReceive();
PORTD=i;
}
}
从机程序:
/***************************************/
/* 设置为从机方式 */
/***************************************/
void SPI_SlaveInit(void)
{DDRD=0XFF;
DDRB=0XD3
PORTB=0X2C;
SPCR=0X40;
}
char SPI_SlaveReceive(void)
{
while(!(SPSR & (1<<SPIF))) {;}/*Wait for reception complete*/
return SPDR; /*Return data register*/
}
/***************************************/
/* 主程序 */
/***************************************/
int main (void)
{char i;
SPI_SlaveInit();
while(1)
{PORTD=SPI_SlaveReceive();}
}
电路图ourdev_496194.pdf(文件大小:20K) (原文件名:spi.pdf) mega8不知道,我没有用过.
干脆给个完整的程序,自己研究吧。
/*****************************************************
This program was produced by the
CodeWizardAVR V1.25.3 Professional
Automatic Program Generator
?Copyright 1998-2007 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com
Project :
Version :
Date : 2007-2-15
Author :
Company :
Comments:
Chip type : ATmega48V
Clock frequency : 8.000000 MHz
Memory model : Small
External SRAM size : 0
Data Stack size : 128
*****************************************************/
#include <mega48.h>
#include <delay.h>
#define SPI_RX_BUFFER_SIZE 6
#define SPI_RX_BUFFER_MASK ( SPI_RX_BUFFER_SIZE - 1 )
#define SPI_TX_BUFFER_SIZE 3
#define SPI_TX_BUFFER_MASK ( SPI_TX_BUFFER_SIZE - 1 )
#define SPI_SET_MASTER SPCR|=(1<<4)
#define SPI_INT_EANBLE SPCR|=(1<<7)
#define SET_SPI_BUS_MODE PORTB.2
#define GET_SPI_BUS_MODE PINB.2
flash unsigned char Tab[]={
0x3F, //0
0x06, //1
0x5B, //2
0x4F, //3
0x66, //4
0x6D, //5
0x7D, //6
0x07, //7
0x7F, //8
0x6F, //9
0x77, //A
0x7C, //B
0x39, //C
0x5E, //D
0x79, //E
0x71 //F
};
bit spi_m;
bit spi_trans_com;
bit spi_sending;
bit blank_state;
bit send_failure;
bit disp_blanking;
unsigned char SPI_RxBuf;
volatile unsigned char SPI_RxHead;
unsigned char SPI_TxBuf;
volatile unsigned char SPI_TxHead;
volatile unsigned char disp_buffer;
volatile unsigned char disp_buffer2;
volatile unsigned char disp_digit;
//TIMER0 initialize - prescale:1024
// WGM: CTC
// desired value: 10mSec
// actual value: 10.112mSec (-1.1%)
void timer0_init(void)
{
TCCR0B = 0x00; //stop
TCNT0 = 0x00; //set count
OCR0A=0x16;
TCCR0A = 0x02;
TCCR0B = 0x05; //start timer
}
// Timer 0 output compare A interrupt service routine
interrupt void timer0_compa_isr(void)
{
PORTD=0x00;
PORTB|=0x03;
PORTC.4=1;
PORTC.5=1;
PORTC&=0xF0;
switch(disp_digit)
{
case 7:
{
PORTB.1=0;
}break;
case 6:
{
PORTB.0=0;
}break;
case 5:
{
PORTC.5=0;
}break;
case 4:
{
PORTC.4=0;
}break;
case 3:
{
if(disp_blanking==0||blank_state==0)
PORTC.3=1;
}break;
case 2:
{
if(disp_blanking==0||blank_state==0)
PORTC.2=1;
}break;
case 1:
{
if(disp_blanking==0||blank_state==0)
PORTC.1=1;
}break;
case 0:
{
if(disp_blanking==0||blank_state==0)
PORTC.0=1;
}break;
default:break;
}
PORTD=disp_buffer;
if(disp_digit<7)
disp_digit++;
else
disp_digit=0;
}
//TIMER1 initialize - prescale:1024
// WGM: 4) CTC, TOP=OCRnA
// desired value: 500mSec
// actual value: 499.968mSec (0.0%)
void timer1_init(void)
{
TCCR1B = 0x00; //stop
OCR1AH = 0x0A;
OCR1AL = 0x41;
TCCR1A = 0x00;
TCCR1B = 0x0D; //start Timer
}
// Timer 1 output compare A interrupt service routine
interrupt void timer1_compa_isr(void)
{
TCCR0B=0x00;
if(blank_state==1)
{
blank_state=0;
disp_buffer=disp_buffer2;
disp_buffer=disp_buffer2;
disp_buffer=disp_buffer2;
disp_buffer=disp_buffer2;
}
else
{
blank_state=1;
disp_buffer=disp_buffer2;
disp_buffer=disp_buffer2;
disp_buffer=disp_buffer2;
disp_buffer=disp_buffer2;
}
TCCR0B=0x05; //start timer
}
// Timer 2 output compare interrupt service routine
interrupt void timer2_compa_isr(void)
{
// Place your code here
}
//******************************************
// SPI 中断服务程序
//******************************************
interrupt void spi_isr(void)
{
unsigned char data;
if(spi_m==0) //如果spi_m为0,表明是接收状态
{
data = SPDR; //读入接受到的数据
SPI_RxBuf = data; //将接收到的数据存入接收缓存区
if ( SPI_RxHead ==( SPI_RX_BUFFER_MASK+2)) //如果是接收帧的最后一个数据
{
if(GET_SPI_BUS_MODE==1)
{
SPI_RxHead = 0; //已接收数据还原
SPI_SET_MASTER; //接收完成,将SPI设回主方式
spi_trans_com=1; //置接收完成标志
}
/*DDRB.2=1;
SET_SPI_BUS_MODE=0; */ //处理数据中,禁止发送方发送
}
else
{
SPI_RxHead++; //已接收数据计数器加1
}
}
else //如果spi_m为1,表明是发送状态
{
if ( SPI_TxHead <= SPI_TX_BUFFER_MASK) //如果要发送的数据还未全部发完
{
SPDR = SPI_TxBuf; //从发送缓存区取数发送
SPI_TxHead++; //已发送数据计数器加1
}
else //如果要发送的数据已全部发完
{
SPI_TxHead=0; //已发送数据计数器还原
DDRB.2=0;
SET_SPI_BUS_MODE=1; //释放总线,以便接收方进入主发送。
spi_m=0;
spi_sending=0; //清空发送中标记
}
}
}
//******************************************
// SPI 初始化
//******************************************
void InitSPI(void)
{
SPI_RxHead = 0;
SPI_TxHead = 0;
SPCR=0xD2;
// Clear the SPI interrupt flag
#asm
nop
in r30,spsr
in r30,spdr
#endasm
}
//******************************************
//发送数据
//******************************************
void spi_send(void)
{
unsigned char temp;
delay_us(50);
if(spi_sending==0) //发送中标记为0,表明spi发送空闲
{
spi_sending=1; //置spi_sending标志表明发送进行中
SPI_TxBuf=0;
for(temp=0;temp<SPI_TX_BUFFER_MASK;temp++) //计算校验和
{
SPI_TxBuf+=SPI_TxBuf;
}
//fill_tx_buffer(); //调用fill_tx_buffer函数,将要发送的数据加载到发送缓冲区
if(GET_SPI_BUS_MODE==0) //如果PINB.2为低,表明总线被接受方占用,等待直至接受方发送完成。
{
for(temp=0;temp<200;temp++)
{
delay_us(100);
if(GET_SPI_BUS_MODE==1)
{
break;
}
}
}
if(temp<100)
{
InitSPI(); //初始化spi为主方式
DDRB.2=1;
SET_SPI_BUS_MODE=0; //将PORTB.2拉低,强迫接收方进入从接收方式
spi_m=1; //置spi_m标志表明为发送状态
delay_us(10);
SPDR=0xFF; //开始发送
SPI_INT_EANBLE; //开SPI中断,
SPI_TxHead = 0; //已发送数据计数器清0
send_failure=0;
}
else
{
send_failure=1;
spi_sending=0;
}
}
}
//*********************************************************
//设定显示数值
//*********************************************************
void set_disp_vol(void)
{
int data;
unsigned char i;
data=(int)SPI_RxBuf*0x100+SPI_RxBuf;
if((data>9999&&SPI_RxBuf==0x00)||(data>999&&SPI_RxBuf==0x01)) // 如果超出显示范围,显示“----“
{
for(i=0;i<4;i++)
disp_buffer=0x40;
}
else
{
for(i=0;i<4;i++)
{
disp_buffer=Tab; //查字形表
data/=10;
}
switch(SPI_RxBuf) //消零
{
case 0:
{
for(i=3;i>0;i--)
{
if(disp_buffer==0x3F)
disp_buffer=0;
else
break;
}
} break;
case 1:
{
for(i=3;i>1;i--)
{
if(disp_buffer==0x3F)
disp_buffer=0;
else
break;
}
} break;
case 2:
{
if(disp_buffer==0x3F)
disp_buffer=0;
} break;
default:break;
}
if(SPI_RxBuf>0&&SPI_RxBuf<4)
disp_buffer]|=0x80; //显示小数点
}
if(SPI_RxBuf==0x01) //显示负号
{
disp_buffer=0x40;
}
}
/*inline send_rx_ok(void)
{
while(spi_sending==1);
SPI_RxBuf=0x00;
SPI_RxBuf=0x00;
spi_send();
} */
void spi_bus_waiting(void)
{
unsigned char temp=0;
while(spi_sending==1)
{
delay_us(10);
temp++;
if(temp>100||spi_sending==0)
{
spi_sending=0;
break;
}
}
}
void read_rx_buffer(void)
{
unsigned char check_sum,temp;
DDRB.2=1;
SET_SPI_BUS_MODE=0; //处理数据中,禁止发送方发送
check_sum=0;
for(temp=0;temp<SPI_RX_BUFFER_MASK;temp++) //计算校验和
{
check_sum+=SPI_RxBuf;
}
if(SPI_RxBuf==check_sum)//校验正确
{
switch (SPI_RxBuf)
{
case 0x00://总线传输状态代码
{
if( SPI_RxBuf==0x01) //受到出错代码,重发
{
spi_send();
}
}break;
case 0x10://功能错误代码
{
TCCR0B=0x00;
disp_buffer=0x79; //E
disp_buffer=0x40; //-
disp_buffer=Tab%10]; //查字形表
SPI_RxBuf/=10;
disp_buffer=Tab%10];
TCCR0B=0x05;
//send_rx_ok();
}break;
case 0x20://显示数据
{
TCCR0B=0x00;
set_disp_vol();
TCCR0B=0x05;
//send_rx_ok();
}break;
case 0x30://led灯数据
{
//TCCR0B=0x00;
disp_buffer2=SPI_RxBuf;
disp_buffer2=SPI_RxBuf;
disp_buffer2=SPI_RxBuf;
disp_buffer2=SPI_RxBuf;
//TCCR0B=0x05;
//send_rx_ok();
}break;
case 0x31://led灯数据
{
//TCCR0B=0x00;
disp_buffer2=SPI_RxBuf;
disp_buffer2=SPI_RxBuf;
disp_buffer2=SPI_RxBuf;
disp_buffer2=SPI_RxBuf;
//TCCR0B=0x05;
//send_rx_ok();
}break;
case 0x40://显示命令
{
if(SPI_RxBuf==0x00) //关闪烁
{
disp_blanking=0;
}
if(SPI_RxBuf==0x01) //闪烁
{
disp_blanking=1;
}
//send_rx_ok();
}break;
case 0x50://显示程序号
{
TCCR0B=0x00;
disp_buffer=0x73; //P
disp_buffer=0x40; //-
disp_buffer=Tab%10]; //查字形表
SPI_RxBuf/=10;
disp_buffer=Tab%10];
TCCR0B=0x05;
//send_rx_ok();
}break;
case 0x60://显示文字
{
TCCR0B=0x00;
disp_buffer=SPI_RxBuf;
disp_buffer=SPI_RxBuf;
disp_buffer=SPI_RxBuf;
disp_buffer=SPI_RxBuf;
TCCR0B=0x05;
//send_rx_ok();
}break;
default:break;
}
}
else //校验失败,发送出错代码
{
spi_bus_waiting();
SPI_TxBuf=0x00;
SPI_TxBuf=0x01;
spi_send();
}
spi_trans_com=0;
DDRB.2=0;
SET_SPI_BUS_MODE=1; //处理完,允许发送方发送
}
void main(void)
{
// Declare your local variables here
// Crystal Oscillator division factor: 1
#pragma optsize-
CLKPR=0x80;
CLKPR=0x00;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif
// Input/Output Ports initialization
// Port B initialization
// Func7=In Func6=In Func5=Out Func4=In Func3=Out Func2=In Func1=Out Func0=Out
// State7=T State6=T State5=0 State4=P State3=0 State2=P State1=0 State0=0
PORTB=0x14;
DDRB=0x2B;
// Port C initialization
// Func6=In Func5=Out Func4=Out Func3=Out Func2=Out Func1=Out Func0=Out
// State6=T State5=0 State4=0 State3=0 State2=0 State1=0 State0=0
PORTC=0x00;
DDRC=0x3F;
// Port D initialization
// Func7=Out Func6=Out Func5=Out Func4=Out Func3=Out Func2=Out Func1=Out Func0=Out
// State7=0 State6=0 State5=0 State4=0 State3=0 State2=0 State1=0 State0=0
PORTD=0x00;
DDRD=0xFF;
timer0_init();
timer1_init();
// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: 125.000 kHz
// Mode: Normal top=FFh
// OC2A output: Disconnected
// OC2B output: Disconnected
ASSR=0x00;
TCCR2A=0x00;
TCCR2B=0x00;
// External Interrupt(s) initialization
// INT0: Off
// INT1: Off
// Interrupt on any change on pins PCINT0-7: Off
// Interrupt on any change on pins PCINT8-14: Off
// Interrupt on any change on pins PCINT16-23: Off
EICRA=0x00;
EIMSK=0x00;
PCICR=0x00;
TIMSK0=0x02;
TIMSK1=0x02;
TIMSK2=0x00;
// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
ADCSRB=0x00;
InitSPI();
// Global enable interrupts
#asm("sei")
disp_buffer=0xFF;
disp_buffer=0xFF;
disp_buffer=0xFF;
disp_buffer=0xFF;
disp_buffer=0xFF;
disp_buffer=0xFF;
disp_buffer=0xFF;
disp_buffer=0xFF;
disp_buffer2=0xFF;
disp_buffer2=0xFF;
disp_buffer2=0xFF;
disp_buffer2=0xFF;
disp_buffer2=0x00;
disp_buffer2=0x00;
disp_buffer2=0x00;
disp_buffer2=0x00;
//disp_blanking=1;
while (1)
{
if(spi_trans_com==1)
read_rx_buffer();
if(send_failure==1)
spi_send();
};
} 好帖!!!! 正在学,记号 楼主给的程序,要好好研究研究 刚学,看看 我用M16写的SPI请大家看一下,功能是:用74HC595实现串转并,数码管显示0——9
#include<avr/io.h>
#include <util/delay.h>
unsigned char date[]={0x03,0x9f,0x25,0x0d,0x99,0x49,0x41,0x1f,0x01,0x09};
#define SS PB4
#define MOSI PB5
#define MISO PB6
#define SCK PB7
//-------------------------------------------
int main()
{
unsigned char i;
DDRB=0Xb0;
PORTB=0XFF;
SPCR=0X50;//允许SPI工作,高位在前,主机模式,工作方式0,频率选择fosc/4
//SPCR=0X00;//状态寄存器,中断标志和写冲突标志。
while(1)
{
for(i=0;i++;i<9)
{
PORTB|=~(_BV(SS));//开始传送
SPDR=date;
while(!(SPSR&(1<<SPIF)));
_delay_ms(1000);
}
PORTB|=_BV(SS);//禁止传送。
}
}
嘿嘿,学习AVR时间不长,请教了。GCC编译,还在调试中,本程序。希望高手们指教。 学习了 你们这通信都不要协议的啊 MARK mark mark mark! mark! mark mark
页:
[1]
2