2016-08-06 17:15:40 L20902 阅读数 8339
  • AD和DA转换-第1季第16部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第16个课程,主要讲解AD转换和DA转换。目标是理解模拟量和数字量的概念,并且学会使用AD转换来采集现实世界的模拟量。

    2574 人正在学习 去看看 朱有鹏

在数逻的课程中,已经学习过AD转换的概念:将模拟信号采样、量化、编码后转换为数字信号。但是未学习过通过单片机编程,显示结果。

编码分有舍有入、只舍不入两种,量化误差前者更小。=2Vm/(2^n+1  - 1 )

注意,为了达到精确度高、稳定性好的目的,最好将所有器件的模拟地和数字分别连接,最后将模拟地和数字地仅在一点相连。

 

此处,使用的是STC12C5A60S2内部的AD转换。


/* 功能:使用12C5A60S2内部AD读取外部电压,显示在1602上       */

#include "STC12C5A60S2.H"
#include <intrins.h>
sbit RS = P2^6;   //1602定义口  //HZ:EN=P2.2  RS=P2.0  RW=P2.1
sbit RW = P2^5;
sbit EN = P2^7;
#define uchar unsigned char;
#define uint unsigned int;

#define RS_CLR RS=0 
#define RS_SET RS=1
#define RW_CLR RW=0 
#define RW_SET RW=1 
#define EN_CLR EN=0
#define EN_SET EN=1

#define DataPort P0   //连接1602数据口 P0             

uchar da1=0,da2=0,da3=0;
double Data,c;
char a[5]="";         
uchar ADC_Chanul_Turn=0;


void DelayUs2x(unsigned char t)
{   
 while(--t);
}


void DelayMs(unsigned char t)
{
     
 while(t--)
 {
     //大致延时1mS
     DelayUs2x(245);
     DelayUs2x(245);
 }
}
/*------------------------------------------------
              判忙函数
------------------------------------------------*/
 bit LCD_Check_Busy(void) 
 { 
 DataPort= 0xFF; 
 RS_CLR; 
 RW_SET; 
 EN_CLR; 
 _nop_(); 
 EN_SET;
 return (bit)(DataPort & 0x80);   
 }
/*---------
------------------------------------------------*/
 void LCD_Write_Com(unsigned char com) 
 {  
 while(LCD_Check_Busy()); //忙则等待
 RS_CLR; 
 RW_CLR; 
 EN_SET; 
 DataPort= com;          //
 _nop_(); 
 EN_CLR;
 }
/*------------------------------------------------
              写入数据函数
------------------------------------------------*/
 void LCD_Write_Data(unsigned char Data) 
 { 
 while(LCD_Check_Busy()); //忙则等待
 RS_SET; 
 RW_CLR; 
 EN_SET; 
 DataPort= Data; 
 _nop_();
 EN_CLR;
 }

/*------------------------------------------------
                清屏函数
------------------------------------------------*/
 void LCD_Clear(void) 
 { 
 LCD_Write_Com(0x01); 
 DelayMs(5);
 }
/*------------------------------------------------
              写入字符串函数
------------------------------------------------*/
 void LCD_Write_String(unsigned char x,unsigned char y,unsigned char *s)//y为行数,x为横坐标,最后一个是字符 
 {     
 if (y == 0) 
     {     
     LCD_Write_Com(0x80 + x);     //表示第一行
     }
 else 
     {      
     LCD_Write_Com(0xC0 + x);      //表示第二行
     }        
 while (*s) 
     {     
 LCD_Write_Data( *s);     
 s ++;     
     }
 }
/*------------------------------------------------
              写入字符函数
------------------------------------------------*/
 void LCD_Write_Char(unsigned char x,unsigned char y,unsigned char Data) 
 {     
 if (y == 0) 
     {     
     LCD_Write_Com(0x80 + x);     
     }    
 else 
     {     
     LCD_Write_Com(0xC0 + x);     
     }        
 LCD_Write_Data( Data);  
 }
/*------------------------------------------------
              初始化函数
------------------------------------------------*/
 void LCD_Init(void) 
 {
   LCD_Write_Com(0x38);    /*显示模式设置*/ 
   DelayMs(5); 
   LCD_Write_Com(0x38); 
   DelayMs(5); 
   LCD_Write_Com(0x38); 
   DelayMs(5); 
   LCD_Write_Com(0x38);  
   LCD_Write_Com(0x08);    /*显示关闭*/ 
   LCD_Write_Com(0x01);    /*显示清屏*/ 
   LCD_Write_Com(0x06);    /*显示光标移动设置*/ 
   DelayMs(5); 
   LCD_Write_Com(0x0C);    /*显示开及光标设置*/
   }
   
/*------------------------------------------------
                  ADC函数
------------------------------------------------*/ 
void InitADC()//初始AD寄存器
{
         P1ASF=0x03;     //0xff设置P1口全部为ADC通道,P10 P11为输出口
        ADC_RES=0x00;    //清除高8位缓冲数据
        if(ADC_Chanul_Turn%2==0)
        {
            ADC_CONTR=0xF0;    //P10口
            _nop_();
            _nop_();
            _nop_();
            _nop_();
            ADC_CONTR=0xE8;
                
         }
        if(ADC_Chanul_Turn%2==1)   //P11口
        {
            ADC_CONTR=0xF1; 
            _nop_();
            _nop_();
            _nop_();
            _nop_();
            ADC_CONTR=0xE9;    
         }                              
}     

void timer0() interrupt 1      //interrupt 1: 定时器0,interrupt3:定时器3
{
    TH0=(65536-20000)/256;       //高八位,(需要表示Xms的定时,计数器由65536-X数到65536,由于16位,只能分高低位)
    TL0=(65536-20000)%256;     //低八位
    InitADC();
    
}

void adc_isr() interrupt 5      //FLAG标志位置位触发中断,没有设优先级,但是同优先级下定时器0更高
{  
   
   //V_5REF=V_1REF*256/da_ref;
   if(ADC_Chanul_Turn%3==0)                     //外部基准电压
   {    
       da1=ADC_RES;                                   //获取转换结果
       Data=((double)da1/256)*5;     //取八位计算基准电压Data,
       c =Data;
       } 
   if(ADC_Chanul_Turn%3==1)
   {
       da2=ADC_RES;                                  //获取转换结果
       Data=((double)da2/256)*5;     //取八位计算实际值Data,
       c =Data;
       }
   if(ADC_Chanul_Turn%3==2)
   {
       da3=ADC_RES;                                  //获取转换结果
       Data=((double)da3/256)*5;     //取八位计算实际值Data,
       c =Data;
       }
      
   a[0]=((int)c%10+0x30);//个位(电压<5,仅有个)     //0x30: ASCAI码里代表“0”,必须转换成字符存在字符型数组里才可以在1602液晶屏上显示
   a[1]=0x2e;                    //小数点
   a[2]=((int)(c*10)%10+0x30); // 十分位
   a[3]=((int)(c*100)%10+0x30);// 百分位
   a[4]='\0';                  //  加了串尾符才成了字符串哦

   if(ADC_Chanul_Turn%3==0)  LCD_Write_String(0,0,a);
   if(ADC_Chanul_Turn%3==1)  LCD_Write_String(5,0,a);
   if(ADC_Chanul_Turn%3==2) LCD_Write_String(0,1,a); 
   
   ADC_CONTR&=0xEF;               //标志位清零
   
   ADC_Chanul_Turn++;
   if(ADC_Chanul_Turn==252) 
      ADC_Chanul_Turn=0;    
}
void main()
{
    LCD_Init(); 
    LCD_Clear();                     //清屏
    DelayMs(255);
    TH0=(65536-20000)/256;           //开定时器0
    TL0=(65536-20000)%256;
    EA=1;                             //开全局中断
    ET0=1;                             //允许定时器零中断
    EADC=1;                          //允许ADC中断 
    TR0=1;       
    while(1);
}


2014-08-22 14:03:38 bluewhaletech 阅读数 2285
  • AD和DA转换-第1季第16部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第16个课程,主要讲解AD转换和DA转换。目标是理解模拟量和数字量的概念,并且学会使用AD转换来采集现实世界的模拟量。

    2574 人正在学习 去看看 朱有鹏

S12系列单片机的AD转换特性

AD转换就是模数转换,就是把模拟信号转换成数字信号。Freescale的S12系列单片机的AD转换模块有以下特点:

1) 转换精度可配置:8位/10位/12位

2) 在STOP模式下,使用内部时钟可以进行AD转换

3) 完成AD转换后自动进入低功耗模式

4) AD采样时间可配置

5) 转换结果数据可配置左对齐或右对齐

6) 可配置转换完成产生中断

7) 模拟输入的8通道可复用

8) 转换序列长度可选1-8

9) 连续转换模式

10)多通道扫描

 

S12系列单片机寄存器介绍

下面以MC9S12HY64芯片为例介绍AD转换相关的常用寄存器,Freescale其他8位/16位芯片的AD转换寄存器也类似

1)控制寄存器ATDCTL0

WRAP:设置多通道转换模式下的环绕通道,在多通道(MULT = 1)模式下,当设置的环绕通道AD转换完成后通道会转到AN0,例如WRAP设置为AN5,那么AN5通道AD转换完成后,AD转换通道就转到AN0,AN6和AN7就不会进行AD转换。

2)控制寄存器ATDCTL1

ETRIGSEL,ETRIGCH:设置外部触发源

SRES:转换精度,可配置为8位/10位/12位

3)控制寄存器ATDCTL2

AFFC:AD转换完成快速标志位清零,AFFC=0状态标志位需手动清零,AFFC=1每次读取结果寄存器标志位自动清理

ICLKSTP:STOP模式下AD转换采用内部时钟工作使能位

ETRIGLE,ETRIGP:外部触发类型设置

ETRIGE:外部触发模式设置

ASCIE:AD转换序列完成中断使能位

ACMPIE:AD比较中断使能位

4)控制寄存器ATDCTL3

DJM:转换结果对齐方式,DJM=0转换结果左对齐,DJM=1转换结果右对齐

S8C,S4C,S2C,S1C:转换序列的长度,如果多通道一次只转换AN4-AN7,那长度就配置成4,如果是单通道,配置成4,那就是对转换的通道连续转换4次

FIFO:AD转换结果的存储模式,AD转换的结果按顺序存在结果寄存器中,当FIFO=0时,每次AD转换序列开始都是从ATDDR0开始存储转换结果,当FIFO=1时,每次AD转换序列开始都是从上一个序列结束时的存储结果的寄存器的后一个开始,所有转换结果都是循环存储(即存储到ATDDR9后,返回ATDDR0,再从ATDDR0-ATDDR9存储),例如要转换的为通道5、6、7,转换模式为连续转换(SCAN=1),当FIFO=0时,每次转换序列的转换结果都是存储在ATDDR0-ATDDR2中;当FIFO=1时,第一次转换序列的结果存储在ATDDR0-ATDDR2中,第二次转换序列的结果存储在ATDDR3-ATDDR5中,以此类推

ETRIGE:外部触发模式设置

ASCIE:AD转换序列完成中断使能位

ACMPIE:AD比较中断使能位

5)控制寄存器ATDCTL4

SMP:采样时间

PRS:AD转换器时钟预分频,fATDCLK=fBUS/(2*(PRS+1))

6)控制寄存器ATDCTL5

ATDCTL5寄存器写入值后会停止当前的AD转换并开始新的AD转换

SC:特殊通道转换位

SCAN:连续转换模式,SCAN=0单次转换,SCAN=1连续转换

MULT:多通道模式,MULT=0单通道转换,MULT=1多通道转换

CD,CC,CB,CA:转换通道选择,对于单通道模式,确定AD转换的通道;对于多通道模式,确定AD转换的首通道

7)状态寄存器ATDSTAT0

SCF:转换序列完成标志位,SCF为0表示当前转换序列未完成,为1表示当前转换序列完成。当出现以下情况时,SCF 标志位清零a.寄存器写入1;b. ATDCTL5写入值;c. AFFC=1并读取结果寄存器。

ETORF:外部触发覆盖标志位

FIFOR:结果寄存器覆盖写入标志位

CC:转换计数器,只读,代表存放当前AD转换结果的结果寄存器

8)状态寄存器ATDSTAT2

CCF:独立通道转换完成标志位

9)AD数字输入信号使能寄存器ATDDIEN

IEN:输入信号输入使能位

10)结果寄存器ATDDR0- ATDDR9

AD转换结果寄存器,左对齐结果数据存储格式如图1所示:


图1

右对齐结果数据存储格式如图2所示:


图2


S12系列单片机AD转换的应用举例

了解了AD转换模块的相关寄存器,就可以根据实际工程的需要来配置相应的寄存器,实现符合项目需求的AD转换功能呢,主要需要配置采样时间,使用的AD转换通道,转换结果的对齐方式,是否需要产生中断等

例如,如果当前项目采用了AD5,AD6,AD7三路AD转换,这三路AD转换精度为12位,不采用中断方式,那么根据这些需求,我们就可以对AD模块进行初始化及对结果进行查询读取,以下是相关代码

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* @Purpose:  A/D Convertion Driver
* @Author:  Purple
* @Version:  1.0
* @Date:  Create By Purple 2014.08.20
* 
* 
* Copyright (C) BlueWhale Tech.   
* All rights reserved.  
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */


#ifndef A2DDRV_H
#define A2DDRV_H


/* Include Files */


/* Macros */
#define A2D_BEGIN_CHANNEL  5
#define A2D_END_CHANNEL  7
#define A2D_CHANNEL_NUMS  (A2D_END_CHANNEL-A2D_BEGIN_CHANNEL+1)

/* Variables */
extern unsigned short int A2DResults[A2D_CHANNEL_NUMS];


/* Function Prototypes */
void A2DInit(void);
void A2DConvert(void);


#endif
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* @Purpose:  A/D Convertion Driver
* @Author:  Purple
* @Version:  1.0
* @Date:  Create By Purple 2014.08.20
* 
* 
* Copyright (C) BlueWhale Tech.   
* All rights reserved.  
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */


/* Include Files */
#include "A2DDrv.h"


/* Variables */
unsigned short int A2DResults[A2D_CHANNEL_NUMS];


/* Function Definitions */
/*
 * FunctionName: A2DInit
 * Purpose: A/D转换模块初始化
 * Parameters: 无
*/
void A2DInit(void)
{
	ATDDIEN = 0x00;    //AD通道输入关闭
	ATDCTL1 = 0x40;    //设置AD转换精度为12位
	ATDCTL2 = 0x00;
	ATDCTL3 = 0x80;    //转换结果右对齐,FIFO模式关闭
	ATDCTL3 |=((unsigned char)A2D_CHANNEL_NUMS<<3);    //设置转换序列的长度
	ATDCTL4 = 0x63;    //设置AD采样时间
	ATDCTL5 |= AD_BEGIN_CHANNEL;   //设置AD采样的首通道
	ATDCTL5_MULT=1;   //设置多通道模式,开始AD转换
}

/* Function Definitions */
/*
 * FunctionName: A2DConvert
 * Purpose: A/D转换结果查询读取
 * Parameters: 无
*/
void A2DConvert(void)
{
	unsigned char i;
	
	while(!ATDSTAT0_SCF);    //等待转换序列完成
	
	for(i=0;i

另外,使用AD转换需要注意以下几点:

1.对于AD转换的精度并不是越高越好,因为转换精度越高,转换结果波动也越大,转换精度越低,转换结果波动也越小,所以要根据项目的实际需求选择合适的转换精度。

2. AD转换使用多通道时应保持使用的通道口连续,这样会方便软件处理。



2015-12-15 09:55:21 u013151320 阅读数 8078
  • AD和DA转换-第1季第16部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第16个课程,主要讲解AD转换和DA转换。目标是理解模拟量和数字量的概念,并且学会使用AD转换来采集现实世界的模拟量。

    2574 人正在学习 去看看 朱有鹏

PCF8591是一个单片集成、单独供电、低功耗、8-bit CMOS数据获取器件。

AD转换即(模拟量)Analog 转换成 (数字量)Digital

1.引脚分析

这里写图片描述

PCF8591具有4个模拟输入(AIN0~AIN3)、1个模拟输出(AOUT)和1个串行I²C总线接口(SDA、SCL)。
PCF8591的3个地址引脚A0, A1和A2可用于硬件地址编程,允许在同个I2C总线上接入8个PCF8591器件,而无需额外的硬件。在PCF8591器件上输入输出的地址、控制和数据信号都是通过双线双向I2C总线以串行的方式进行传输。
OSC:外部时钟输入端,内部时钟
EXT:内部、外部时钟选择线,使用内部时钟时 EXT 接地。
VDD、VSS:电源端。
AGND:模拟信号地。
VREF:基准电源端。

2.应用分析

AD转换部分电路图:

这里写图片描述

要求:使用LCD1602将电压值显示出来,调节变阻器改变电压值

说明:以下代码中用到了LCD1602驱动程序和I2C总线驱动程序,请参考博主51单片机栏目下的博客。

#define uint unsigned int
#define uchar unsigned char
/*查阅pcf8591的资料可知它的都写地址如下*/
#define  WRITEADDR 0x90    //写地址
#define  READADDR  0x91    //读地址
uchar dat[6];

void Pcf8591SendByte(uchar channel)
{   
    I2C_Start();    //关于I2C总线,请参照博主博文:51单片机I2C总线驱动程序
    I2C_SendByte(WRITEADDR);        //发送写器件地址
    I2C_SendByte(0x40|channel);     //发送控制寄存器
    I2C_Stop();
}

uchar Pcf8591ReadByte()
{
    uchar num;
    I2C_Start();
    I2C_SendByte(READADDR);      //发送读器件地址
    dat=I2C_ReadByte();          //读取数据
    I2C_Stop();                  //结束总线
    return num;
}

void main()
{
    uint adNum,i;
    float value;
    Lcd1602_init();   //关于lcd1602,请参照博主博文:51单片机LCD1602程序详解
    while(1)
    {
            Pcf8591SendByte(0);      //使用通道0
            /*adNum一定是0到255之间的一个数,因为pcf8591是8位的AD/DA芯片,所以输出的范围为00000000到11111111,即0到255*/
            adNum=Pcf8591ReadByte();   //读出数值
            /*将adNum转换成电压值,单片机的电压为5V,则电位器的电压为0到5V,用0到255表示0到5V,则每一个1代表5/255V,即0.01953V*/
            value=adNum*0.01953;  //转为电压值
            adNum=value*100;        //保留两位小数,以便显示出来

            dat[0]=adNum/1000+'0';      //加上'0'是表示数字转换成字符,1602只能显示字符
            dat[1]=adNum%1000/100+'0';
            dat[2]='.';
            dat[3]=adNum%100/10+'0';
            dat[4]=adNum%10+'0';
            dat[5]='V';
            Lcd1602_WriteCom(0x80);    
            for(i=0;i<6;i++)
            {
               Lcd1602_WriteData(dat[i]);
            }
    }
}
2019-12-02 20:48:41 tyfwin 阅读数 124
  • AD和DA转换-第1季第16部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第16个课程,主要讲解AD转换和DA转换。目标是理解模拟量和数字量的概念,并且学会使用AD转换来采集现实世界的模拟量。

    2574 人正在学习 去看看 朱有鹏

51单片机AD转换、串口蓝牙通讯、labview上位机显示

功能:单片机模拟数字转化,将数字信号通过蓝牙或者串口传输给电脑,电脑上labview显示出一个图表。

我这里实际使用是探测光信号强弱的:

 光信号——>光电探测器——>单片机电压转化为数字信号(AD转化)——>单片机通过串口发送出——>labview接收显示

 

单片机采用非常简单,别人常说它垃圾,可能确实有点垃圾,但是我却很喜欢的stc12c5a60s2,自带AD转化,有2个串口美滋滋,引脚图如下:

我使用P1.1口作为模拟信号输入,P1.3作为串口把数据实时传输出去。

voltagetemp_int=(int)(voltagetemp*1000);
voltagetemp_a = voltagetemp_int /100;
voltagetemp_b = voltagetemp_int %100;
UartSendChar('l');
UartSendChar('m');
UartSendChar(voltagetemp_a);
UartSendChar(voltagetemp_b);
UartSendChar('n');
UartSendChar('o');

根据上面代码,可以知道,传出去的数据,自己为了弄一个校验识别,先发送字符l和m,再发送真实数据,再发送字符n和o表示这一次数据发送结束。模拟信号电压真实值在0-5v之间,这里为了精度高一点显示,先乘以1000,再把高2位和低2位分别取出来,分别发送出去。

 

还是以前本科时候写的主要代码C语言,拿过来改改用,或许不是很规范。问题很大。懒得改了。

完事之后文件夹如下。

 

主函数代码:ceshi.c


#include <12c5a60s2.h>

#include "intrins.h"

#include <stc12delay.h>

#include <ADchange.h>

#include  <math.h>

#include  <uart.h>

int light=0;

uint scan_num=0;

float voltagetemp=0;

int  voltagetemp_int=0;

int  voltagetemp_a=0;

int  voltagetemp_b=0;

int t_int=0;

void main()

{

UartInit();

AD_init();

    while(1)

   {

scan_num++;

 if(scan_num>30)

 {

    scan_num=0;

AD_get(1);

light=initvoltage1;delay(1);

    voltagetemp=light/1024.0*5;

    voltagetemp_int=(int)(voltagetemp*1000);

    voltagetemp_a = voltagetemp_int /100;

voltagetemp_b = voltagetemp_int %100;

// UartSendChar(voltagetemp_int);

    UartSendChar('l');

UartSendChar('m');

UartSendChar(voltagetemp_a);

UartSendChar(voltagetemp_b);

UartSendChar('n');

UartSendChar('o');

 }

}

}

————

ADchange.h内容如下:

idata uint initvoltage1;

void AD_init()

{

P1ASF=0x03;  //P1  0 1 口作为模拟功能AD使用

ADC_RES=0;   //清零转换结果寄存器高8位

ADC_RESL=0; //清零转换结果寄存器低2位

ADC_CONTR=0x80;//开启AD电源  

delay(1);   //等待1ms,让AD电源稳定

}



void AD_get(char channel)  //我这里只能取0 和 1 通道

{  

ADC_CONTR=0x88|channel;    //开启AD转换1000 1000 自定通道 即POWER SPEED1 SPEED0 ADC_FLAG  ADC_START CHS2 CHS1 CHS0

_nop_(); _nop_(); _nop_(); _nop_();//要经过4个CPU时钟的延时,其值才能够保证被设置进ADC_CONTR 寄存器

while(!(ADC_CONTR&0x10));    //等待转换完成

ADC_CONTR&=0xe7;      //关闭AD转换,ADC_FLAG位由软件清0

initvoltage1=ADC_RES*4+ADC_RESL;

//voltagetemp=initvoltage1/1024.0*5;

//FtoS(voltagetemp);

//return str;   //返回AD转换完成的10位数据(16进制)

}

 

————

stc12delay.h内容如下:

 #ifndef __STC12DELAY_H__

#define __STC12DELAY_H__



#define uchar unsigned char

#define uint unsigned int





/*****相关宏定义***/

    /* exact-width signed integer types */

typedef   signed          char int8_t;

typedef   signed short     int int16_t;

typedef   signed           int int32_t;

typedef   signed       long int int64_t;



    /* exact-width unsigned integer types */

typedef unsigned          char uint8_t;

typedef unsigned short     int uint16_t;

typedef unsigned           int uint32_t;

typedef unsigned       long int uint64_t;





////11.0592    1T

void delay01ms() //@11.0592MHz

{

unsigned char i, j;



_nop_();

i = 11;

j = 190;

do

{

while (--j);

} while (--i);

}



 //延时n ms

void delaynms(unsigned int n)

{   unsigned int i;

for(i=0;i<n;i++)

delay01ms();

}

//也是延时 n  ms

void delay(unsigned int n)

{   unsigned int i;

for(i=0;i<n;i++)

delay01ms();

}



////11.0592    1T

void delay1ms12(void)   //误差 -0.018084490741us

{

    unsigned char a,b,c;

    for(c=8;c>0;c--)

        for(b=197;b>0;b--)

            for(a=2;a>0;a--);

}



void delaynms12 (unsigned int n)

{   unsigned int i;

for(i=0;i<n;i++)

delay1ms12();

}



#endif


 

 

————

uart.h内容如下:

  


void UartInit();

void UartSendChar(unsigned char ch); //向外发送字节

void UartSendStr(unsigned char *pStr); //向外发送字符串



void UartInit()

{

//串口2,用于舵机控制器

//串口1,用于接收上位机发出指令

     S2CON = 0x50; // SCON: serail mode 1, 8-bit UART  定时器1作为波特率的发生器

 SCON = 0x50;

 AUXR=0X15;

 BRT=(int)(256-((11059200/9600)/32));

 EA = 1;

 ES = 1;

}



//串口2有关

void UartSendChar(unsigned char ch)   //向外发送字节

{

    S2BUF = ch;

    while(!(S2CON&S2TI));

    S2CON&=~S2TI;

}

void UartSendStr(uchar *pStr)     //向外发送字符串

{

    while(*pStr != 0)

     {

        S2BUF = *pStr++;

        while(!(S2CON&S2TI));

     S2CON&=~S2TI;

     }

}  

把生成的hex文件下载到单片机之后,单片机就不停的向串口发送:l,m,数据1,数据2,n,o,l,m,数据1,数据2,n,o, l,m,数据1,数据2,n,o, ……

 

好,然后是labview做的上位机界面的接收,显示。

 

先看界面情况:

 

然后看前面板程序:

 

先配置串口(和单片机内配置保持一致就行了),电脑上就可以选择串口号,包括蓝牙也可以直接选择电脑蓝牙对应的串口号:

 

再经过一个while循环,循环内进行主要数据的接受和处理。先visa读取数据,这里每次读取10个数据,一边直接显示在缓存区,同时下面接一根线将其转化为图标。

 

 

下面将visa读取的数据实际上是一个字符类型的,转化为字节数组。

下面接for循环,来解析分别把这个10个元素的一维数组内的数据索引出来。

 

 

索引数组就是脚本语言中的a[5],把a数组中第6个元素取出来。

下面就分别把这个数组中,a[i],a[i+1],a[i+2],a[i+3]这4个元素分别拿出来。i是遍历的从0-9。

然后判断,如果满足a[i] =109,a[i+3]=110,(109和110分别是asc的字符mn) 那么 把a[i+1]和a[i+2]这2真实数据拿出来进行一个类型转换,转化为真实的电压数据显示出来即可。

 

完整的labview代码如下:

 

Over~

 

 

2010-11-01 10:52:00 Baiduluckyboy 阅读数 2467
  • AD和DA转换-第1季第16部分

    本课程是《朱有鹏老师单片机完全学习系列课程》第1季第16个课程,主要讲解AD转换和DA转换。目标是理解模拟量和数字量的概念,并且学会使用AD转换来采集现实世界的模拟量。

    2574 人正在学习 去看看 朱有鹏
单片机AD转换程序 TLC2543
目前电子大赛在如火如荼的进行着,本人现在把自己在大学期间调试的一些东西贡献出来,希望能够帮到需要的人
谢谢!
完成功能:将TLC2543的通道0进行AD转换并以静态显示方式在LED上显示
使用不同的通道可以根据需要做相应用的修改即可
大家看的主要就是AD的子程序,显示和主程序只是为帮助清析脉络而写的。
**********************************************************/
#include<reg52.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int

/*下面是引脚连接关系*/
sbit AD_EOC   =P2^4;   /*转换完成指示*/
sbit AD_IOCLK =P2^3;         /*时 钟*/
sbit AD_DATIN =P2^2;   /*数据入*/
sbit AD_DATOUT=P2^1;   /*数据出*/
sbit AD_CS    =P2^0;   /*片 选*/

sbit SCLK=P3^1;
sbit SDA=P3^0;
uint ad_result;    /*存各模拟通道的数据*/

/*启动A/D转换,并读取上次转换结果*/
uint read2543(CHN)
{
uchar i,temp;
uint read_ad_data = 0;
CHN=CHN<<4;
AD_IOCLK=0;
AD_CS=1;
AD_CS=0;
temp=CHN;
for(i=0;i<12;i++)
{
   read_ad_data=read_ad_data<<1;
   if((temp&0x80)!=0){AD_DATIN=1;}
   else{AD_DATIN=0;}
   if(AD_DATOUT){read_ad_data=read_ad_data+1;}
   AD_IOCLK =1;
   _nop_();_nop_();_nop_();_nop_();
   AD_IOCLK =0;
   _nop_();_nop_();_nop_();_nop_();
   temp=temp<<1;
}
AD_CS=1;
read_ad_data=read_ad_data&0x0fff;
return(read_ad_data);
}

/*显示用的时钟程序*/
void i_clock(void)
{
SCLK=0;
SCLK=1;
SCLK=0;
}

/************显示程序*************/
void led(void)
{uchar code LEDValue[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90}; //0-9
uchar data num[6];
uchar k,s,DAT;
num[0]=1;
num[1]=0;
num[2]=ad_result/1000;
num[3]=(ad_result-ad_result/1000*1000)/100;
num[4]=(ad_result-ad_result/100*100)/10;
num[5]=ad_result-ad_result/10*10;         //*0.0012;

for(k=0;k<=5;k++)
{
   DAT=LEDValue[num[5-k]];
   for(s=0;s<8;s++){
   SDA=(bit)(DAT&0x01);
   DAT>>=1;
   i_clock();
   }
}
}
/************延时程序*************/
void delay(del)
{
for(del;del>0;del--);
}
/*主 程序*/
void main(void)
{
delay(100);
ad_result=read2543(0); ///*启动0通道转换,第一次转换结果不准确,丢弃*/
do{
     while(!AD_EOC);            /*等待转换完成*/
     ad_result=read2543(0);///*读转换结果,并启动下次转换*/
   led();
delay(5000);
}while(1);
}

PIC单片机之AD转换

阅读数 17955

AD 转换

阅读数 412

没有更多推荐了,返回首页