打印
[AVR单片机]

mega16的SPI通信问题

[复制链接]
3400|6
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
走过路过千万不要一笑而过……
向路过的各位大侠请教个问题:

小弟菜鸟只学过51汇编,没有学过C,没有学过AVR

现在要用到AVR,遇到点麻烦,请大侠帮帮忙,谢谢。。。

初来咋到,分不多,大家别嫌少,帮帮忙,3Q

atmega16和12位ADC的SPI通信,我弄了半天,也没有弄通,请大家帮忙看看程序:

ADC芯片资料在附件: mcp3204.pdf (1.44 MB) mega16芯片: mega16-16L_cn.pdf (2.83 MB)
菜鸟的程序:
AVR硬件SPI:
unsigned char Get_mcp3204_val(void)
{
unsigned int i;
  float j;
i = mcp3204_SPI();
j = (i*5)/4096;
//这里只取转换结果整数部分验证一下通信是否成功先
j = (unsigned char)j;
return(j);
}
unsigned int mcp3204_SPI(void)
{
unsigned int temp,temp1;
DDRB =(1<<PB7)|(~(1<<PB6))|(1<<PB5)|(1<<PB4);
PORTB = (1<<PB7)|(1<<PB6)|(~(1<<PB5))|(1<<PB4);
SPCR = (1<<SPE)|(1<<MSTR)|(1<<CPOL)|(1<<CPHA)|(1<<SPR1)|(1<<SPR0);//
PORTB &=(~(1<<PB4));//启动通信
SPSR = 0x00;
SPDR = 0x07;//发送起始位和SGL,D2位
while(!SPSR&(1<<SPIF));
PORTB &=(1<<PB4);
SPSR = 0x00;
SPDR = 0x3f;//发送D1D0
while(!SPSR&(1<<SPIF));
SPSR = 0x00;
temp = SPDR;//接受高四位
while(!SPSR&(1<<SPIF));
SPSR = 0x00;
temp1 = SPDR;//接受低8位
while(!SPSR&(1<<SPIF));
PORTB &=(1<<PB4);
temp = (unsigned int)temp<<8;
temp = (unsigned int)((temp|temp1)&0x0fff);
return(temp);
}

软件模拟SPI:
#include<avr/io.h>
#include"delay.h"
#include"display.h"
#define CS PB4
#define DO PB6
#define DI PB5
#define CLK PB7
unsigned int SPI_mcp3204(void);
int main(void)
{
while(1)
{
  unsigned char temp;
  unsigned int m,n;
  m = SPI_mcp3204();
  n = (m*5)/4096;
  temp = (unsigned char)n;
  display(temp);
}
}
unsigned int SPI_mcp3204(void)
{
unsigned char j;
unsigned int i = 0;
DDRB = 0xbf;
PORTB = 0xff;
//发送启动位和SGL,D2,D1,D0
PORTB &=(~(1 << CS));
PORTB &=(~(1 << CLK));
PORTB &= (1<< DI);//1
PORTB &=(1 << CLK);
asm("nop");
PORTB &=(~(1 << CLK));
PORTB &= (1<< DI);//1
PORTB &=(1 << CLK);
asm("nop");
PORTB &=(~(1 << CLK));
PORTB &=(~(1 << DI));//0
PORTB &=(1 << CLK);
asm("nop");
PORTB &=(~(1 << CLK));
PORTB &=(~(1 << DI));//0
asm("nop");
PORTB &=(1 << CLK);
//采样周期
asm("nop");
PORTB &=(~(1 << CLK));
asm("nop");
PORTB &=(1 << CLK);
//空位
asm("nop");
PORTB &=(~(1 << CLK));
asm("nop");
PORTB &=(1 << CLK);
//读取转换结果
for(j =12;j > 0; j--)
{
  asm("nop");
  PORTB &=(~(1 << CLK));
  asm("nop");
  i = ((PINB&0x40) >> PB6);
  i <<=1;
  PORTB &=(1 << CLK);
}
PORTB &= (1 << CS);//拉高片选
i >>= 1;
return(i);
}

相关帖子

沙发
此心向学|  楼主 | 2010-7-24 22:41 | 只看该作者
图:

使用特权

评论回复
板凳
此心向学|  楼主 | 2010-7-25 11:01 | 只看该作者
没人回答啊

使用特权

评论回复
地板
宇宙飞船| | 2010-7-25 11:16 | 只看该作者
什么项目要用到12位的ADC?
是音频吗?音频要求的是16位精度,就算楼主想选用32位机,没有外挂ADC也无济于事。
若果是一般的项目,10位ADC也很好用了,楼主可否把项目的要求说明一下,俺可以帮忙分析一下硬件,看哪些地方可以优化,使最终使用一块MCU就能实现。

使用特权

评论回复
5
此心向学|  楼主 | 2010-7-25 11:52 | 只看该作者
很不好意思啊,是我没有理解好AVR硬件的SPI,闹出了笑话。
下面把可以通信的程序贴出来:
unsigned int mcp3204_SPI(void)
{
        static unsigned int temp,temp1;
        DDRB =(1<<PB7)|(~(1<<PB6))|(1<<PB5)|(1<<PB4);
        PORTB = (1<<PB7)|(1<<PB6)|(1<<PB5)|(1<<PB4);
        SPCR = (1<<SPE)|(1<<MSTR)|(1<<CPOL)|(1<<CPHA)|(1<<SPR1)|(1<<SPR0);//
        PORTB &=(~(1<<PB4));//启动通信
        temp = SPIWrite(0x07);
        temp = SPIWrite(0x3f);
        temp1 = SPIWrite(0xff);
        PORTB &=(1<<PB4);
        temp = (unsigned int)temp<<8;
        temp = (unsigned int)((temp|temp1)&0x0fff);
        return(temp);

}


unsigned char SPIWrite(unsigned char data)
{
                SPDR = data;
                while(!(SPSR & (1<<SPIF)));
          return (SPDR);
}

使用特权

评论回复
6
此心向学|  楼主 | 2010-7-25 11:56 | 只看该作者
非常感谢版主,
要用到两路adc转换,分辨率至少要12位,速率也不能太慢,
估计后面还得用到两通道的12位DAC。
10位的分辨率不够。 4# 宇宙飞船

使用特权

评论回复
7
此心向学|  楼主 | 2010-7-25 11:59 | 只看该作者
读取SPDR不能用temp = SPDR;
只能用return(SPDR);吗

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

0

主题

70

帖子

1

粉丝