打印
[AVR单片机]

avr单片机SPI通讯,采集24路AD信号

[复制链接]
2858|3
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
au529|  楼主 | 2012-7-9 11:48 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
/*************************************************
mcu:主机atmega169
使用模块:SPI通讯,AD转换查询模式

*************************************************/
#include <iom169v.h>
#include <macros.h>
#define SET_RS PORTD|=0x01
#define SET_RW PORTD|=0x02
#define SET_EN PORTD|=0x04
#define CLR_RS PORTD&=0x01
#define CLR_RW PORTD&=0x02
#define CLR_EN PORTD&=0x04
#define MAX_AD 4940  
#define MIN_AD 4905
#define LCD_DATA  PORTE     
/*****12864地址矩阵*****/
unsigned char addr_tab[32]={     
0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,
0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,
0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,
0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,
};
/*****毫秒延时函数*****/
void delay_ms(unsigned int t)     
{
unsigned int i;
while(t--)
{
  for(i=0;i<125;i++);
}        
}
void delay_us(unsigned char n)
{
if (n == 0)
{  
return ;  
}
while (--n);
}
/*****LCD写命令函数*****/
void Lcd_WriteCmd(unsigned char cmdcode)
{
    LCD_DATA = cmdcode;
        CLR_RS;
    CLR_RW;
    SET_EN;       
delay_us(5);   
    CLR_EN;
}
/*****LCD写数据函数*****/
void Lcd_WriteData(unsigned char dispdata)
{
    LCD_DATA = dispdata;
        SET_RS;
    CLR_RW;
    SET_EN;       
delay_us(5);   
    CLR_EN;
}
/*****LCD初始化函数*****/
void LCD_init()
{   
delay_ms(50);
    Lcd_WriteCmd(0x34);        
delay_ms(10);
    Lcd_WriteCmd(0x30);         
delay_ms(1);
    Lcd_WriteCmd(0x0C);         
delay_ms(1);
    Lcd_WriteCmd(0x01);         
delay_ms(20);
}
/*****LCD写字符串函数*****/
void LCD_write_str(unsigned char x,unsigned char y,unsigned char *s)
{        
Lcd_WriteCmd(addr_tab[8*x+y]);  
while(*s>0)
           {       
  Lcd_WriteData(*s);   
  s++;     
    }
}
/*******LCD写连续两个字符函数*************/
void LCD_write_num(unsigned char x,unsigned char y,unsigned char num1,unsigned char num2)
{        
Lcd_WriteCmd(addr_tab[8*x+y]);   
  Lcd_WriteData(num1);
  Lcd_WriteData(num2);     
}
/********LCD写单个字符函数****************/
void LCD_write_char(unsigned char x,unsigned char y,unsigned char data)
{
  Lcd_WriteCmd(addr_tab[8*x+y]);     
  Lcd_WriteData(data);     
}
/********AD模块初始化函数**************************/
void ADC_init(unsigned char td,unsigned char xt)
{
    PORTA= xt;
        ADMUX = td;                       //选择AVCC,结果右对齐,选择ADC通道0
    ADCSRA = 0x86;                      //ADC模块使能,未开始转换,自动触发关闭,中断关闭,预分频比16
    ADCSRB = 0x00;
        DIDR0=0xFF;         
}
/********AD模块转化函数*******************************/
void ADC_convert()
{
   unsigned char i;
   for(i=0;i<=1;i++)
   {
   ADCSRA |= 1<<ADSC;       
   while(!(ADCSRA&(1<<ADIF)));                //查询方式等待转换完成   
   ADCSRA &= ~(1 << ADIF);      
   }
   ADCSRA &= ~(1 << ADEN);
}
/********端口初始化函数**************************/
void PORT_init()
{DDRA=0xFF;
PORTA=0x00;
DDRC=0xFF;
PORTC=0xFF;
DDRB=0xF7;  //11110111
PORTB=0xFF;
DDRE=0xFF;
DDRF=0x00;
PORTF=0x00;
DDRD=0xFF;
PORTD=0xFF;
}
/*********SPI初始化为主机函数*************/
void SPI_MasterInit()
{
        DDRB |= (1<<PB1) | (1<<PB2);                /* 设置MOSI 和SCK 为输出,其他为输入 */
        SPCR = (1<<SPE) | (1<<MSTR)
                | (1<<SPR1) | (1<<SPR0);                /* 使能SPI主机模式,设置时钟速率为fck/128 */
}
/*********1#从机SPI发送接收数据函数*****************/
unsigned char SPI_masterout(unsigned char xt)
{       
        PORTB &= ~(1 <<PORTB4); //强制从机模式
        SPDR = xt;                                                        /* 启动数据传输 */
        while (!(SPSR & (1<<SPIF)));       
        PORTB |= (1 <<PORTB4);        //解除从机模式
        SPCR |= (1<<MSTR); // MSTR有时会被清零,这里强制进入主机模式          
        return SPDR;       
}
/*********2#从机SPI发送接收数据函数***************************/
unsigned char SPI_masterout2(unsigned char xt)
{       
        PORTB &= ~(1 <<PORTB5); //强制从机模式
        SPDR = xt;                                                        /* 启动数据传输 */
        while (!(SPSR & (1<<SPIF)));       
        PORTB |= (1 <<PORTB5);        //解除从机模式
        SPCR |= (1<<MSTR); // MSTR有时会被清零,这里强制进入主机模式          
        return SPDR;       
}
/*********主函数******************/
void main(void)
{
  unsigned char tdzj[8]={0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47};
  unsigned char xtzj[8]={0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01};  
  unsigned char td[8]={0x60,0x62,0x64,0x66,0x70,0x72,0x74,0x76};
  unsigned char xt[8]={0x61,0x63,0x65,0x67,0x71,0x73,0x75,0x77};  
  unsigned char i;
  unsigned long int adc;

  unsigned char spireceive;
  unsigned char by_disp_seg[4];
  unsigned char hang[8]={0,0,1,1,2,2,3,3};
  unsigned char lie1[8]={2,6,2,6,2,6,2,6};
  unsigned char lie2[8]={3,7,3,7,3,7,3,7};
  unsigned char adczj[8]={0,0,0,0,0,0,0,0};
  unsigned char adcc1[8]={0,0,0,0,0,0,0,0};
  unsigned char adcc2[8]={0,0,0,0,0,0,0,0};
  PORT_init();
  SPI_MasterInit();
  LCD_init();
  delay_ms(20);
  LCD_init();   
  LCD_write_str(0,0,"请开始测试");
  LCD_write_str(1,1,"按下start 键");
  LCD_write_str(2,0,"");
  LCD_write_str(3,3,"");
  delay_ms(2000);  
  while(1)
  {
    LCD_init();         
    LCD_write_str(0,0," c1: .   c2: .  ");
    LCD_write_str(1,0," c3: .   c4: .  ");
    LCD_write_str(2,0," c5: .   c6: .  ");
    LCD_write_str(3,0," c7: .   c8: .  ");
        for(i=0;i<=7;i++)
     {
          ADC_init(tdzj[i],xtzj[i]);
                  delay_ms(50);
                  ADC_convert();
                  adc=ADC;
                  adc*=5000;
                  adc/=1023;
                  if(adc>=MAX_AD||adc<=MIN_AD)
                  {
                  adczj[i]=1;
                  }               
          by_disp_seg[0]=adc%10+0x30;
          adc/=10;
          by_disp_seg[1]=adc%10+0x30;
          adc/=10;
          by_disp_seg[2]=adc%10+0x30;
                  adc/=10;
                  by_disp_seg[3]=adc%10+0x30;
                  LCD_write_char(hang[i],lie1[i],by_disp_seg[3]);   
          LCD_write_num(hang[i],lie2[i],by_disp_seg[2],by_disp_seg[1]);                              
            }
          PORTA=0x00;          
          delay_ms(200);   
          LCD_init();
      LCD_write_str(0,0," c9: .  c10: .  ");                              
      LCD_write_str(1,0,"c11: .  c12: .  ");
      LCD_write_str(2,0,"c13: .  c14: .  ");
      LCD_write_str(3,0,"c15: .  c16: .  ");            
          spireceive=SPI_masterout(0x10);                    
          spireceive=SPI_masterout(0x10);                   
          for(i=0;i<=7;i++)                    
        {         
             spireceive=SPI_masterout(td[i]);
             LCD_write_char(hang[i],lie1[i],spireceive);
                 adc=spireceive;
                 adc=adc<<8;
                 delay_ms(25);
                 spireceive=SPI_masterout(xt[i]);
                 adc+=spireceive;                                  
                  adc*=5000;
                  adc/=1023;
                  if(adc>=MAX_AD||adc<=MIN_AD)
                  {
                  adcc1[i]=1;
                  }               
          by_disp_seg[0]=adc%10+0x30;
          adc/=10;
          by_disp_seg[1]=adc%10+0x30;
          adc/=10;
          by_disp_seg[2]=adc%10+0x30;
                  adc/=10;
                  by_disp_seg[3]=adc%10+0x30;
                  LCD_write_char(hang[i],lie1[i],by_disp_seg[3]);   
          LCD_write_num(hang[i],lie2[i],by_disp_seg[2],by_disp_seg[1]);                        
          delay_ms(25);  
         }                      
          delay_ms(800);          
          LCD_init();            
      LCD_write_str(0,0,"c17: .  c18: .  ");                              
      LCD_write_str(1,0,"c19: .  c20: .  ");
      LCD_write_str(2,0,"c21: .  c22: .  ");
      LCD_write_str(3,0,"c23: .  c24: .  ");                 
          spireceive=SPI_masterout2(0x20);          
          spireceive=SPI_masterout2(0x20);          
          for(i=0;i<=7;i++)                    
        {         
             spireceive=SPI_masterout2(td[i]);
             LCD_write_char(hang[i],lie1[i],spireceive);
                 adc=spireceive;
                 adc=adc<<8;
                 delay_ms(25);
                 spireceive=SPI_masterout2(xt[i]);
                 adc+=spireceive;                         
                 adc*=5000;
                  adc/=1023;
                  if(adc>=MAX_AD||adc<=MIN_AD)
                  {
                  adcc2[i]=1;
                  }               
          by_disp_seg[0]=adc%10+0x30;
          adc/=10;
          by_disp_seg[1]=adc%10+0x30;
          adc/=10;
          by_disp_seg[2]=adc%10+0x30;
                  adc/=10;
                  by_disp_seg[3]=adc%10+0x30;
                  LCD_write_char(hang[i],lie1[i],by_disp_seg[3]);   
          LCD_write_num(hang[i],lie2[i],by_disp_seg[2],by_disp_seg[1]);                         
          delay_ms(25);  
         }                 
          delay_ms(800);          
          LCD_init();
      LCD_write_str(0,0,"不合格的是:");      
          for(i=0;i<=7;i++)
          {
          if(adczj[i]>=1)
          {LCD_write_char(1,i,0x31+i);
          adczj[i]=0;}
          else
          {}
          }
          if(adcc1[0]>=1)
          {
          LCD_write_char(2,0,0x39);
          adcc1[0]=0;
          }
          else
          {}
          for(i=1;i<=7;i++)
          {
          if(adcc1[i]>=1)
          {LCD_write_num(2,i,0x31,0x2F+i);
          adcc1[i]=0;
          }
          else
          {}
          }
          for(i=0;i<=2;i++)
          {
          if(adcc2[i]>=1)
          {LCD_write_num(3,i,0x31,0x37+i);
          adcc2[i]=0;}
          else
          {}
          }
          for(i=3;i<=7;i++)
          {
          if(adcc2[i]>=1)
          {
          LCD_write_num(3,i,0x32,0x2D+i);
          adcc2[i]=0;
          }
          else
          {}
          }          
          delay_ms(2000);  
   }  
}

/******************************************
mcu:atmega8
使用模块:SPI从机中断方式,AD转换查询方式
******************************************/
#include <iom8v.h>
#include <macros.h>
void delay_us(unsigned char n)
{
if (n == 0)
{  
return ;  
}
while (--n);
}
/*********毫秒延时函数***************/
void delay_ms(int time)
{
int i;
for(;time>0;time--)
  for(i=0;i<1000;i++);
}
/**********AD初始化函数********************/
void ADC_init(unsigned char td)
{   
        ADMUX = td;                       //选择AVCC,结果右对齐,选择ADC通道0
    ADCSRA = 0x86;                      //ADC模块使能,未开始转换,自动触发关闭,中断关闭,预分频比16
}
/***********AD转换函数查询方式*********************/
void ADC_convert()
{
   unsigned char i;
   for(i=0;i<=2;i++)
   {
   ADCSRA |= 1<<ADSC;       
   while(!(ADCSRA&(1<<ADIF)));                //查询方式等待转换完成   
   ADCSRA &= ~(1 << ADIF);      
   }
   ADCSRA &= ~(1 << ADEN);   
}
/************端口初始化函数*******************/
void PORT_init()
{
DDRD=0xFF;
PORTD=0x00;
DDRC=0x00;
PORTC=0x00;
DDRB=0xEB;
PORTB=0x00;
}
/*************SPI初始化为从机***********************/
void SPI_SlaveInit(void)
{
/* 设置MISO 为输出,其他为输入 */
DDRB |= (1<<PB4);
SPCR =0xC0;  //使能SPI
SPSR=0x00;  
}
void main()
{
CLI();
PORT_init();
SPI_SlaveInit();
MCUCR=0x00;
GICR=0x00;
TIMSK=0x00;
PORTD=0x80;
ADC_init(0x47);
ADC_convert();
PORTD=0x00;
SEI();
while(1)
  {   
  }
}

#pragma interrupt_handler SPI_stc_isr: iv_SPI_STC
void SPI_stc_isr()
{
unsigned int adc;
unsigned char adcl;
unsigned char adch;
switch(SPDR)
{
case 0x10:
SPDR=0x11;
while (!(SPSR & (1<<SPIF)));
adc=ADC;
adcl=adc;
adc=adc>>8;
adch=adc;
SPDR=adch;
PORTD=0x40;
break;

case 0x60:
adc=ADC;
adcl=adc;
adc=adc>>8;
adch=adc;
SPDR=adcl;
ADC_init(0x46);
ADC_convert();
break;

case 0x61:
adc=ADC;
adcl=adc;
adc=adc>>8;
adch=adc;
SPDR=adch;
PORTD=0x20;
break;

case 0x62:
adc=ADC;
adcl=adc;
adc=adc>>8;
adch=adc;
SPDR=adcl;
ADC_init(0x45);
ADC_convert();
break;

case 0x63:
adc=ADC;
adcl=adc;
adc=adc>>8;
adch=adc;
SPDR=adch;
PORTD=0x10;
break;

case 0x64:
adc=ADC;
adcl=adc;
adc=adc>>8;
adch=adc;
SPDR=adcl;
ADC_init(0x44);
ADC_convert();
break;

case 0x65:
adc=ADC;
adcl=adc;
adc=adc>>8;
adch=adc;
SPDR=adch;
PORTD=0x08;
break;

case 0x66:
adc=ADC;
adcl=adc;
adc=adc>>8;
adch=adc;
SPDR=adcl;
ADC_init(0x43);
ADC_convert();
break;

case 0x67:
adc=ADC;
adcl=adc;
adc=adc>>8;
adch=adc;
SPDR=adch;
PORTD=0x04;
break;

case 0x70:
adc=ADC;
adcl=adc;
adc=adc>>8;
adch=adc;
SPDR=adcl;
ADC_init(0x42);
ADC_convert();
break;

case 0x71:
adc=ADC;
adcl=adc;
adc=adc>>8;
adch=adc;
SPDR=adch;
PORTD=0x02;
break;

case 0x72:
adc=ADC;
adcl=adc;
adc=adc>>8;
adch=adc;
SPDR=adcl;
ADC_init(0x41);
ADC_convert();
break;

case 0x73:
adc=ADC;
adcl=adc;
adc=adc>>8;
adch=adc;
SPDR=adch;
PORTD=0x01;
break;

case 0x74:
adc=ADC;
adcl=adc;
adc=adc>>8;
adch=adc;
SPDR=adcl;
ADC_init(0x40);
ADC_convert();
break;

case 0x75:
adc=ADC;
adcl=adc;
adc=adc>>8;
adch=adc;
SPDR=adch;
PORTD=0x80;
break;

case 0x76:
adc=ADC;
adcl=adc;
adc=adc>>8;
adch=adc;
SPDR=adcl;
ADC_init(0x47);
ADC_convert();
break;

case 0x77:
SPDR=0x10;
PORTD=0x00;
break;

default:
break;
}

}

相关帖子

沙发
zaiming| | 2012-7-24 18:03 | 只看该作者
你好!请问有原理图吗?

使用特权

评论回复
板凳
au529|  楼主 | 2013-1-9 14:31 | 只看该作者
有,但是这个方案虽然已经调通,但是单片机本身AD采集的精度达不到测试要求,改了个AD芯片的方案。

使用特权

评论回复
地板
逆旅以南| | 2015-5-11 16:40 | 只看该作者
您好,我刚上班,领导安排做一个24路电压采集和分别显示(0-5V,精确到小数点后两位)的方案,我只会51系列单片机,端口不够用啊,如您方便,能否帮忙给个解决方案,万谢!

使用特权

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

本版积分规则

2

主题

28

帖子

1

粉丝