视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
温度PID控制
2025-09-27 23:39:38 责编:小OO
文档
一、实验名称:51系列单片机闭环温度控制实验

——基于Protuse仿真实验平台实现

基本情况:

1. 学生姓名:

2. 学    号:

3. 班    级:

4. 实验项目组长:

5. 同组其他成员:

序号姓     名

班    级

学    号

分工系数
1
2
6. 具体分工:

 组长 电路设计仿真 整合实验报告

 组员 相关资料收集 

 组员 程序编写

7. 本人在项目组的作用描述:

  主要负责实验方案的确定,电路设计仿真和实验报告的整理及完成

  主要负责实验前相关资料的收集和试验中主要原理的收集

  主要负责C语言程序编写,根据电路仿真图及实验要求,编写程序

二、实验内容(实验原理介绍):

1、实验原理

利用ATC51单片机可以方使地实现对PID参数的选择与设定;也可以通过计算机与单片机的串行通讯,实现工业过程中的交互式PID控制。它是用温度传感器将检测到的实际炉温A/D转换,送入计算机中,与设定值进行比较,得出偏差。对此偏差按PID算法进行修正,求得对应的控制量控制可控硅驱动器,调节电炉的加热功率,从而实现对炉温的控制。因此采集的炉温数据精度至关重要。利用C51单片机实现温度智能控制,能自动完成数据采集、处理、缓冲、转换、并进行PID实施控制和键盘终端处理及显示,包括各参数数值的修正。但在控制过程中应该注意,采样周期不能太短,否则使调节过于频繁,不但执行机构不能反应,而且计算机的利用率大为降低。采样周期太长,也是不合适,因为干扰无法及时消除,使调节品质下降。随着单片机在各行业控制系统中的普遍采用,其构成的实时控制系统日臻完善,使该温度控制系统的总体性能大大提高,功能更趋完善,并详细介绍了该系统的软、硬件实施手段及系统特点。同时可以通过键盘对PID的参数进行设定,把实时的速度反馈回来经过PID进行调节,并将调节后的转速通过显示界面液晶1602显示出来。

2、元件简介

2.1、TLC2543

TLC2543是是一种数模转换器芯片,是TI公司的12位串行模数转换器,使用开关电容逐次逼近技术完成A/D转换过程。由于是串行输入结构,能够节省51系列单片机I/O资源;且价格适中,分辨率较高,因此在仪器仪表中有较为广泛的应用。

  TLC2543具有以下特点:

(1)12位分辩率A/D转换器;

(2)在工作温度范围内10μs转换时间;

(3)11个模拟输入通道;

(4)3路内置自测试方式;

(5)采样率为66kbps;

(6)线性误差±1LSBmax;

(7)有转换结束输出EOC;

(8)具有单、双极性输出;

(9)可编程的MSB或LSB前导;

(10)可编程输出数据长度。 

2.2 ATC51

ATC51是一个低电压,高性能CMOS 8位单片机,片内含8k bytes的可反复擦写的Flash只读程序存储器和256 bytes的随机存取数据存储器(RAM),器件采用ATMEL公司的高密度、非易失性存储技术生产,兼容标准MCS-51指令系统,片内置通用8位处理器和Flash存储单元,ATC52单片机在电子行业中有着广泛的应用。

 通用微处理器,采用工业标准的C51内核,在内部功能及管脚排布上与通用的8xc52 相同,其主要用于会聚调整时的功能控制。功能包括对会聚主IC 内部寄存器、数据RAM及外部接口等功能部件的初始化,会聚调整控制,会聚测试图控制,红外遥控信号IR的接收解码及与主板CPU通信等。主要管脚有:XTAL1(19 脚)和XTAL2(18 脚)为振荡器输入输出端口,外接12MHz 晶振。RST/Vpd(9 脚)为复位输入端口,外接电阻电容组成的复位电路。VCC(40 脚)和VSS(20 脚)为供电端口,分别接+5V电源的正负端。P0~P3 为可编程通用I/O 脚,其功能用途由软件定义,在本设计中,P0 端口(32~39 脚)被定义为N1 功能控制端口,分别与N1的相应功能管脚相连接,13 脚定义为IR输入端,10 脚和11脚定义为I2C总线控制端口,分别连接N1的SDAS(18脚)和SCLS(19脚)端口,12 脚、27 脚及28 脚定义为握手信号功能端口,连接主板CPU 的相应功能端,用于当前制式的检测及会聚调整状态进入的控制功能。2.3、Proteus基本操作

(一)启动Proteus仿真软件:双击“isis”图标,出现isis操作页面。

(二)搭建单片机系统仿真电路:分“器件选取”、“器件放置”和“电路连接”  三大步来操作。

〖第一步器件选取〗:

isis操作页面的左侧中下部分是电路和器件操作的导航区域,器件选取前“Devices”栏目下为空,器件选取操作的目的是将从器件库中分拣出需要的器件,这些器件排列在“Devices”栏目下。

A:先选择“器件和仪器工具栏”的“放大器符号样”图标(该工具栏的第一个图标),再单击“P”键即弹出“Pick Devices”窗口。Pick Devices窗口左侧可以输入器件类型名称,或者选择器件类型,窗口中部即出现相应类型的器件,若鼠标选中器件,窗口右侧会出现该器件的引脚图和封装图。

B:在Pick Devices窗口中,先选中器件,后点击窗口右下脚的“确定”按钮,即将器件排列在“Devices”栏目下了。或者直接双击被选的器件,也能收到同样的操作结果。

C:对于电源、地、输入和输出端等特殊器件,不在“Pick Devices”窗口中选取而在“Pick Terminals”窗口中选取。只要选择“器件和仪器工具栏”的“输入输出符号样”图标(该工具栏的第八个图标),即变“Devices”栏目为“Terminals” 栏目,“Terminals” 栏目下已经将电源、地、输入和输出端等特殊器件列出了一部分,如还要增加时,单击“P”键即弹出“Pick Terminals”窗口供选取。

〖第二步器件放置〗:

isis操作页面的中右侧是搭建硬件电路系统原理图和显示系统运行状态的区域。器件放置前或选择“New Design”文件后,器件放置区域同导航区一样栏目内容为空,器件放置操作是把导航区的器件排列在放置区的适当位置,以便于搭建硬件电路系统原理图。

A:器件放置的基本操作:是将导航区的器件选中(左键),然后把鼠标移到放置区中适当位置,再点击左键,即放置了器件。若多次点击左键,则会放置多个相同的器件。

B:器件的移动、翻转和删除操作:在放置区中选中器件的方法是用右键点击一次,被选中的器件变成红色,然后用鼠标选中红色的器件再按住左键移动鼠标即移动了器件位置,移动后器件仍然是红色,移动完成后将鼠标移开器件至空白处再点击右键,红色器件变回黑色。器件翻转的方法是右键选中器件使之变红,然后将鼠标移至导航区下方,点击红色的翻转图标,即可实现器件的翻转,完成后将鼠标移回放置区空白处再点击右键,红色器件变回黑色。器件删除的的方法是右键选中器件使之变红,再对变红的器件点击右键,即删除了相应的器件。

C:器件和图形的复制操作:在放置区中,按住鼠标右键适当移动鼠标即画出一个矩形方框,方框内部的器件和图形变成红色,这时再点击菜单下的复制图标和粘贴图标,即会复制出一个相同的方框图形,移动鼠标即可将复制的图形移到适当的位置,再点击左键定位,若定位之前点击右键即删除复制的图形。

D:器件属性的设置:在放置区中右键选中器件后器件变红,再点击左键即弹出“Edit Component”对话框,该对话框内容即器件的属性,其中的一些内容可以选择隐藏不被显示出来。

〖第三步电路连接〗:

搭建硬件电路系统原理图需要把器件的引脚连接起来,其操作比较简单。

A:电路连接操作方法:将鼠标移至一个引脚或一条连线上点击左键,再移动鼠标即拉出一条红色导线,导线要拐弯时,则点击左键再移动鼠标即拉出拐弯的导线,最后导线的另一端通常要接到另一个引脚或另一条连线上,再点击左键导线变回黑色完成连接。若只对导线两端要求正确连接,对导线路由不作要求,则鼠标只需对连接导线始端和末端的引脚进行点击左键,便自动完成布线。

B:电路连接快速操作方法:若需要连接的两个器件的引脚都按照一个方向的顺序、等距离地排列,那么只需对第一条导线进行人工布线,从第二条导线开始顺序双击连接导线始端的引脚即可完成对应的导线连接。 

C:导线的删除操作:右键选中导线后导线变红,再对变红的导线点击右键即删除了导线。

D:导线属性的设置:右键选中导线后导线变红,再点击左键即弹出“Edit Wire Style”对话框,即可对导线的属性进行设置。

(三)创建和导入ASM源文件

进入菜单栏,选择“Source”下“Add/Remove Source files…”,即弹出“Add/Remove Source Code Files”对话框。再点击“New”按键,弹出“New Source Files”对话框,即可以创建(只在文件名栏目输入一个文件名,后缀为ASM)或导入ASM源文件。确定后,“Add/Remove Source Code Files”对话框中“Source Code Filename”栏目即有ASM源文件名及路径,然后在“Code Generation Tool”栏目中选择“ASEM51”,最后点击“OK”按键,即完成了创建和导入ASM源文件。此后“Source”下即可以看到相应的ASM源文件。

(四)编译ASM和导入HEX文件

编译ASM文件的前提是已导入ASM文件,启动编译的方法有两种:

方法一:进入菜单栏,选择“Source”下“Build All”,即弹出“BUILD LOG”提示框,提示编译ASM文件的结果。

方法二:直接点击器件放置和运行区下方的“运行”按键,若ASM文件内容有变化,即自动对其编译,若问题即弹出“SOURCE CODE BUILD ERRORS”提示框,提示编译ASM文件的结果。

编译ASM文件成功后即生成HEX文件,单片机导入HEX文件的方法是,打开单片机器件属性对话框,在“Program Files”栏目里打开文件目录,选择装入HEX文件即可。单片机此后按照该HEX文件的代码运行程序。

【特别注意】单片机运行速度与晶振频率有关,目前PROTEUS的版本不支持晶振器属性里所设置的频率值,单片机晶振频率必须在单片机器件本身的属性里设置,即打开单片机器件属性对话框,在其“Clock Frequency” 栏目里输入频率值。

(五)软件调试菜单

进入菜单栏,选择“Debug”下“Start/Resart Debugging”,即进入调试状态,此后可以进行单步运行、全速运行、断点设置等功能。

【特别提示】:调试期间,即可看到电路系统的运行结果和状态细节。可在电路中进行电压、电流和波形测试,其测试操作基本方法是选择“器件和仪器工具栏”的测试工具或测试信号图标,将测试工具和测试信号放置到电路的相应位置,并与测试点连接起来(放置和连接方法同电路器件一样),然后再调试运行即可看到测试结果。

3、模块简介

3.1、温度检测模块

采用铂电阻温度传感器,运用放大电路,把温度的变化转换成铂电阻的变化,该电压经放大进行模数(A/D)转换,放大电路选用单一运放构成差动放大器,放大倍数约200倍左右,运放内设补偿,可承受大的差动输入电压且输入阻抗较高,具体电路如图所示

                图1 温度检测模块

3.2、数据采集模块

             图2 数据采集

3.3、键盘控制PID参数的设定模块

               图3 矩阵键盘

    在键盘中按键数量较多时,为了减少I/O口的占用,通常将按键排列成矩阵形式,如图1所示。在矩阵式键盘中,每条水平线和垂直线在交叉处不直接连通,而是通过一个按键加以连接。这样,一个端口(如P1口)就可以构成4*4=16个按键,比之直接将端口线用于键盘多出了一倍,而且线数越多,区别越明显,比如再多加一条线就可以构成20键的键盘,而直接用端口线则只能多出一键(9键)。由此可见,在需要的键数比较多时,采用矩阵法来做键盘是合理的。

通过键盘可以设置一定量的PID参数,点击“P”“I”“D”,对其进行参数设置,设置完之后,点击“确定”,运行。

三、实验结果分析(含程序、数据记录及分析和实验总结等,可附页):

实验仿真图:

实验数据记录如表:

实验数据记录

数据设定次数实验次数设定温度PIDMAXMIN
199PID  
120.1010098
2120.1010398
323.309999
2139920.10400399
2120.10160148
323.30401399
实验结果分析:

当PID值维持在较小的数值是,温度控制得比较稳定,当增大相对应的参数值到一定的范围内时,温度就会出现较大的波动。尤其是当I至增大时,温度的变化巨大,以至于不能正确反映温度的真实值。

    

编写程序:

#include "Type_Data.h"

#include "1602.h"

#include "TLC2543.h"

#include "Key.h"

#include "PID.h"

#include "stdio.h"

INT32U Count_Num;

INT32U Time_count;

INT8U Flag_SC;

sbit we = P3^7;

void SystemInit(void)

{

    TMOD |= 0x21;

    SCON |= 0x50;

    TH0 = (65536 - 45073) / 256;

    TL0 = (65536 - 45073) % 256;

    

    TR0 = 1;

    ET0 = 1;

    

    TH1 = 0xfd;

    TL1 = 0xfd;

    TR1 = 1;

    TI = 1;//利用printf 要置此为1

    

    EA=1;

}

void main(void)

{

    SystemInit();

    IncPIDInit();

    Init_1602();

    Init_Display();

    while (1)

    {

    if (!Flag_SC)

        PWMOUT();

    else

        PWM = 0;

    }

}

void Interrupt_Time0(void) interrupt 1

{

    TH0 = (65536 - 44083) / 256;

    TL0 = (65536 - 44083) % 256;

    Time_count++;

if (Time_count > 1)

    {

        Time_count = 0;

        if (!Flag_Key)

        {

            Count_Num = Read_TLC2435(1)*0.245-0.308;

            Diaplay_Num_1602(Line1_Address+13,Count_Num);

            printf("%d C\\n",(INT16U)(Count_Num));

            sPID.SetPoint = Set_Speed();

            Diaplay_Num_1602(Line1_Address+3,sPID.SetPoint);

            if (Count_Num > sPID.SetPoint)

            {

                Flag_SC = 1;

            }

            else

            {

                Flag_SC = 0;

            }

            Speed = Count_Num;

            PID_Adjust();

        }

        Key_Option();

    }

}

/***********************

filename:1602.c

data:2013/3/26

/************************/

#include "1602.h"

INT8U code LcdBuf[]= {                //自定义汉字    5X7;最大能存储个字节                                

0x0c,0x12,0x12,0x0c,0x00,0x00,0x00,0x00,

0x0f,0x10,0x10,0x10,0x10,0x10,0x0f,0x00,

};

/***********************************

函数名称:Delay_1602(INT8U time)

函数功能:1602延迟

日期:2013/3/26

备注:无

/***********************************/

void Delay_1602(INT8U time)

{

    while (time--);

}

/***********************************

函数名称:Write_Order_1602(INT8U order)

函数功能:1602写命令

日期:2013/3/26

备注:无

/***********************************/

void Write_Order_1602(INT8U order)

{

    RS_1602 = L;

    RW_1602 = L;

    E_1602  = L;

    Data_1602 = order;

    //Write_Read(order);

    E_1602  = H;

    Delay_1602(10);

    E_1602  = L;

    

}

/***********************************

函数名称:Write_Order_1602(INT8U order)

函数功能:1602写数据

日期:2013/3/26

备注:无

/***********************************/

void Write_Data_1602(INT8U dat)

{

    RS_1602 = H;

    RW_1602 = L;

    E_1602  = L;

    Data_1602 = dat;

    //Write_Read(dat);

    E_1602  = H;

    Delay_1602(10);

    E_1602  = L;    

}

/***********************************

函数名称:Set_xy_1602(INT8U x,INT8U y)

函数功能:1602设置坐标

日期:2013/3/26

备注:无

/***********************************/

void Set_xy_1602(INT8U x,INT8U y)

{

    INT8U address = 0;

    if (y == 1)

        address = 0x80 + x;//第一行

    else

        address = 0xc0 + x;//第二行

        

    Write_Order_1602(address);//写入地址

}

/***********************************

函数名称:Display_String_1602(INT8U x,INT8U y,INT8U *s)

函数功能:1602指定位置显示字符串

日期:2013/3/26

备注:无

/***********************************/

void Display_String_1602(INT8U x,INT8U y,INT8U *s)

{

    Set_xy_1602(x,y);

    while (*s)

    {

        Write_Data_1602(*s);

        s++;

    }

}

/***********************************

函数名称:Write_Order_1602(INT8U order)

函数功能:1602初始化

日期:2013/3/26

备注:无

/***********************************/

void Init_1602(void)

{

    Write_Order_1602(Set_Display_Mode);

    Write_Order_1602(Close_Screen);

    //Write_Order_1602(Open_Cursor_Flicker);

    Write_Order_1602(Open_Ucursor);

}

/***********************************

函数名称:Diaplay_Num_1602(INT16U num)

函数功能:1602显示数

日期:2013/3/26

备注:无

/***********************************/

void Diaplay_Num_1602(INT8U line,INT32U num)

{

    Write_Order_1602(line);

    Write_Data_1602(0x30 + num/100%10);

    Write_Data_1602(0x30 + num/10%10);

    Write_Data_1602(0x30 + num/1%10);

    

}

void Diaplay_Key_Num_1602(INT8U line,INT32U num)

{

    Write_Order_1602(line);

    Write_Data_1602(0x30 + num/10%10);

    Write_Data_1602(0x30 + num/1%10);

    

}

void Write_CGRAM(INT8U *p)

{

    INT8U i,j,kk;

    INT8U tmp=0x40;  //操作CGRAM的命令码

    kk=0;

for(j=0;j<2;j++) // 字节存储空间,可以生成 8 个自定义字符点阵 X8

    {

for(i=0;i<8;i++) // 8 个字节生成 1 个字符点阵

        {

            Write_Order_1602(tmp+i);    //操作CGRAM的命令码+写入CGRAM地址.

            Write_Data_1602(p[kk]);    //写入数据

            kk++;

        }

        tmp += 8; 

    }

void  set_xy(INT8U x,INT8U y)

  switch (x)

   {

        case 0: y+=0x80; break;

     case 1: y+=0xc0; break;

   }

  

  Write_Order_1602(y);

}

 

void  display_onechar(INT8U x,INT8U y,INT8U wdate)

{

     set_xy(x,y);

     Write_Data_1602(wdate);

}

void Init_Display(void)

{

    Write_CGRAM(LcdBuf);             //向CGRAM写入自定义的摄氏度符号

    Display_String_1602(0,1,"SV:000    PV:000");

    Display_String_1602(0,2,"P:02 I:0.1 D:00 ");

    display_onechar(0,6,0);       //显示自定义的摄氏度符号

    display_onechar(0,7,1);      //显示自定义的摄氏度符号

}

/***********************

filename:Key.c

data:2013/3/10

/************************/

#include "Key.h"

#include "PID.h"

BOOL Flag_Key = 0;

BOOL Flag_P,Flag_I,Flag_D;

INT8U temp;

INT8U k = 0;

INT8U Num[3][2];

void Delay(INT8U count)

{

    INT8U x,y;

for (x=count; x>0; x--)

        for (y=110; y>0; y--);

}

/***********************************

函数名称:Key_Num(void)

函数功能:返回键值

调用函数:无

输入值:Key_num

返回值:无

日期:2013/3/10

备注:无

/***********************************/

INT8U Key_Num(void)//返回键值

{

    INT8U Buffer[] = {0xfe,0xfd,0xfb,0xf7};//行编码

    

    INT8U i,j,temp;

    INT8U Key_num;

    

    Key_Port = 0x0f;//消抖

    if (Key_Port != 0x0f)

    {

        Delay(10);

        if (Key_Port != 0x0f)

        {

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

            {

                Key_Port = Buffer[i];

                Delay(200);

                temp = 0x10;//中间变量

                for (j=0; j<4; j++)//列扫描

                {

                    if (!(temp&Key_Port))

                        Key_num = i*4+j+1;

                    temp<<=1;

                }

            }

        }

        return Key_num-1;

    }

    else 

    return 20;

}

void Key_Option(void)

{

    

    INT8U KeySet = 20;

    switch(Key_Num())

    {

        case 0 :KeySet = 21;break;//P

        case 1 :KeySet = 0 ;break;

        case 2 :KeySet = 1 ;break;

        case 3 :KeySet = 2 ;break;

        

        case 4 :KeySet = 22 ;break;//I

        case 5 :KeySet = 3 ;break;

        case 6 :KeySet = 4 ;break;

        case 7 :KeySet = 5 ;break;

        

        case 8 :KeySet = 23 ;break;//D

        case 9 :KeySet = 6 ;break;

        case 10 :KeySet = 7 ;break;

        case 11 :KeySet = 8 ;break;

        

        case 12 :KeySet = 24 ;break;//OK

        case 13 :KeySet = 9 ;break;

        case 14 :KeySet = 25 ;break;//.

        case 15 :KeySet = 20 ;break;

        case 20 :KeySet = 20 ;break;

    }

    //Diaplay_Num_1602(Line2_Address+13,KeySet);

    if (KeySet == 21)

    {

        Flag_Key = 1;

        Flag_P = 1;

        Flag_I = 0;

        Flag_D = 0;

        Write_Order_1602(Open_Cursor_Flicker);

        Write_Order_1602(Line2_Address);

    }

    

    if (Flag_P)

    {

        if (KeySet >= 0 && KeySet<=9)

        {    

            temp = KeySet;

            Num[0][k] = KeySet;

            k++;

            if (k==2)

            k=0;

            Diaplay_Key_Num_1602(Line2_Address+2,Num[0][0]*10+Num[0][1]);

            Write_Order_1602(Line2_Address);

        }

        P_DATA = Num[0][0]*10+Num[0][1];

    }

    

    if (KeySet == 22)

    {

        Flag_Key = 1;

        Flag_P = 0;

        Flag_I = 1;

        Flag_D = 0;

        Write_Order_1602(Open_Cursor_Flicker);

        Write_Order_1602(Line2_Address+5);

    }

    

    if (Flag_I)

    {

        if (KeySet >= 0 && KeySet<=9)

        {    

            temp = KeySet;

            Num[1][k] = KeySet;

            k++;

            if (k==2)

            k=0;

            

            Write_Order_1602(Line2_Address+7);

            Write_Data_1602(0x30 + Num[1][0]);

            Write_Order_1602(Line2_Address+9);

            Write_Data_1602(0x30 + Num[1][1]);

            

            Write_Order_1602(Line2_Address+5);

        }

        I_DATA = Num[1][0] + 0.1*Num[1][1];

    }

    

    if (KeySet == 23)

    {

        Flag_Key = 1;

        Flag_P = 0;

        Flag_I = 0;

        Flag_D = 1;

        Write_Order_1602(Open_Cursor_Flicker);

        Write_Order_1602(Line2_Address+11);

    }

    

    if (Flag_D)

    {

        if (KeySet >= 0 && KeySet<=9)

        {    

            temp = KeySet;

            Num[2][k] = KeySet;

            k++;

            if (k==2)

            k=0;

            Diaplay_Key_Num_1602(Line2_Address+13,Num[2][0]*10+Num[2][1]);

            Write_Order_1602(Line2_Address+11);

        }

        D_DATA = Num[2][0]*10+Num[2][1];

    }

        

    if (KeySet == 24)

    {

        Flag_Key = 0;

        Flag_P = 0;

        Flag_I = 0;

        Flag_D = 0;

        sPID.Proportion =P_DATA; //比例常数Proportional Const

        sPID.Integral =I_DATA; //积分常数Integral Const

        sPID.Derivative =D_DATA; //微分常数Derivative Const

        Write_Order_1602(Open_Ucursor);

    }

    

}

/***********************

filename:1602.c

data:2013/3/26

/************************/

#include "TLC2543.h"

void mdelay(INT8U n)

{

    while (n--);

}

/**************************************

  名称:read2543

  功能:TLC2543驱动模块

  输入参数:port通道号

  输出参数:ad转换值

*************************************/

INT16U Read_TLC2435(INT8U port)

{

    INT16U ad=0,i;

    CLOCK=0;

    _CS=0;

port<<=4;//通道号左移4位

for(i=0;i<12;i++)//没有设置控制字,默认输出数据为12位,高位先送出,输出数据的格式为2进制

    {

      if(D_OUT) ad|=0x01;//转换后的值高位先送出

      D_IN=(bit)(port&0x80);//通道值高位先送出

      CLOCK=1;

      mdelay(3);

      CLOCK=0;

      mdelay(3);

port<<=1;

ad<<=1;

    }

    _CS=1;

ad>>=1;//循环中多左移了一位

    return ad; 

}

INT16U Set_Speed(void)

{

    return (INT16U)(1000 * (Read_TLC2435(0)/4096.0));

}下载本文

显示全文
专题