returnUDR;/*获取并返回数据*/
}
5程序设计及说明
(1)模拟量采集程序设计
系统要采集10路模拟量(10位精度),单片机与TLC1543接口如下:
引脚PA0连接TLC1543的SDO口接收转换后的数据传入,引脚PA1连接TLC1543的ADDR口用来选择通道数,引脚PA2连接TLC1543的_CS用来控制片选,引脚PA3连接TLC1543的CLK以控制时序。
如下图所示:
图11TLC1543与Atmega16引脚接口图
A/D芯片的数据读取程序是根据TLC1543的工作时序来进行设计的。
TLC1543工作时序如图2所示,其工作过程分为两个周期:
访问周期和采样周期。
读CLK有10个周期,前4个周期进行采样通道号的选择,后6个周期进行模拟量的采集,采集子程序是通过CPU通道地址的写操作,发出A/D转换启动脉冲,启动以后单片机查询A/D转换是否结束,一旦结束CPU通过对通道地址的读操作读取数值。
10路模拟量采集程序流程图如下:
(2)开关量采集程序设计
20路开关量采集电路如图8所示,16路开关量通过74LS165芯片将并行输入转换成串行输入(PC0和PC1进行16路开关量采样),剩余的4路开关量直接由单片机I/O(PB0~PB3)进行采样。
20路开关量采集程序流程图如下:
(3)上位机程序设计
本文中采用的是RS-485协议,所以单片机需要采用RS-485接口;而在PC机侧使用的是RS-232与RS-485的电平转换接口。
此次可以采用单片机内部的USART,因此实现串口通讯十分容易,只需要设置适当的寄存器就可以使串口工作起来,串口通讯采用中断机制。
上位机程序负责对数据进行收集和处理,由于是下位机是被动传输,和下位机传输是遵循一定的通讯协议,协议已经在下位机中进行了定义。
当上位机发送一个控制字0x78给下位机时,下位机将会返回所有的数据采集量。
上位机流程图如下:
(3)上位机主程序:
#include
#include
#include
voidInit_COM(intComPortAddr,unsignedcharIntVectNum,imBaud,
unsignedcharData,unsignedcharStop,unsignedcharParity)//串口初始化
intReceiveChar(intport)//接收字符
main()
{inti;chara[500];
voidInit_COM(03F8H,0X0b,9600,8,1,0);
//定义串口端口地址为COM1口,中断处理号为0X0b,波特率为9600,数据位为8,停止位为1,奇偶校验位为0
for(i=0;i<500;i++)
a[i]=ReceiveChar();//每隔一秒接收一个字节}
6设计小结与体会
这次计算机控制课程设计,让我们有机会将课堂上所学的理论知识运用到实际中。
并通过对知识的综合利用,进行必要的分析,比较。
从而进一步验证了所学的理论知识。
同时,这次课程设计也为我们以后的学习打下基础。
指导我们在以后的学习,多动脑的同时,要善于自己去发现并解决问题。
这次的课程设计,还让我知道了最重要的是心态,在你拿到题目时会觉得困难,但是只要充满信心,就肯定会完成的。
通过这次计算机课程设计,我加深了对课本专业知识的理解,平常都是理论知识的学习,在此次课程设计中,真正做到了自己查阅资料、完成一个基本汇编程序的设计。
在此次的设计过程中,我更进一步地熟悉了RS-485通信原理。
当然,在这个过程中我也遇到了困难,通过查阅资料,相互讨论,我准确地找出错误所在并及时纠正了,这也是我最大的收获,使自己的实践能力有了进一步的提高,让我对以后的工作学习有了更大的信心。
回顾起此次计算机控制课程设计,至今我仍感慨颇多。
的确,从选题到定稿,从理论到实践,可以说得是苦多于甜,但是可以学到很多很多的的东西,同时不仅巩固了以前所学过的知识,而且学到了很多在书本上所没有学到过的知识。
通过这次课程设计使我懂得了只有理论知识是远远不够的,只有把所学的理论知识与实践相结合起来,从理论中得出结论,从而提高自己的实际动手能力和独立思考的能力。
在设计的过程中难免会遇到过各种各样的问题,同时在设计的过程中发现了自己的不足之处,对以前所学过的知识理解得不够深刻,掌握得不够牢固,通过这次课程设计,把以前所学过的知识重新温故,巩固了所学的知识。
7参考文献
[1]秦龙.MSP430单片机应用系统开发典型实例.中国电力出版社,2005
[2]于海生.微型计算机控制技术.清华大学出版社,1999
[3]姚四改Protel99SE电子线路设计教程.上海交通大学出版社,2003
[4]朱定华编著.《微机原理、汇编与接口技术学习指导》清华大学出版社,2004
[5]侯玉宝.基于Proteus的51系列单片机设计与仿真.电子工业出版社,2008
附录程序代码
(1)10路模拟量采集程序如下:
//TLC1543端口定义
#defineTLC1543_SDOPA0//数据输入
#defineTLC1543_ADDRPA1//数据输出
#defineTLC1543_/CSPA2//使能端
#defineTLC1543_CLKPA3//时钟端
//read1543()返回10位AD芯片TLC1543的port通道采样值。
uintread1543(ucharport)//从TLC1543读取采样值,形参port是采样的通道号
{
uintdataad;uintdatai;
uchardataal=0,ah=0;
CLK=0;
for(i=0;i<4;i++)//把通道号打入1543
{
ADDR=(bit)(port&0x80);CLK=1;CLK=0;
port<<=1;
}
for(i=0;i<6;i++)//填充6个CLK
{CLK=1;CLK=0;
}
/CS=1;
_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();
_CS=0;//等待AD转换
_nop_();_nop_();_nop_();
for(i=0;i<2;i++)//取D9,D8
{D_OUT=1;
CLK=1;
Ah<<=1;
if(D_OUT)ah|=0x01;
CLK=0;
}
for(i=0;i<8;i++)//取D7--D0
{D_OUT=1;
CLK=1;
al<<=1;
if(D_OUT)al|=0x01;
CLK=0;
}
/CS=1;
ad=(uint)ah;ad<<=8;ad|=(uint)al;//得到AD值
return(ad);
}
(2)开关量数据采集程序
#defineSINPUT_PORTPORTA
#defineSINPUT_DDRDDRA
#defineSINPUT_PINPINA
#defineDIG_PLPD6//PL脚
#defineDIG_CLKPD5//时钟脚
#defineDIG_CE1PB1//片选
#defineDIG_OUT1PC0//串行输出
#defineDIG_OUT2PC1//串行输出
#defineS_PL()CONTROL_PORT|=BIT(DIG_PL)//置1
#defineC_PL()CONTROL_PORT&=~BIT(DIG_PL)//置0
#defineS_CLK()CONTROL_PORT|=BIT(DIG_CLK)//置1
#defineC_CLK()CONTROL_PORT&=~BIT(DIG_CLK)//置0
#defineS_CE1()CONTROL_PORT|=BIT(DIG_CE1)//置1
#defineC_CE1()CONTROL_PORT&=~BIT(DIG_CE1)//置0
#defineS_CE2()CONTROL_PORT|=BIT(DIG_CE2)//置1
#defineC_CE2()CONTROL_PORT&=~BIT(DIG_CE2)//置0
#defineDB_INPUT1(SINPUT_PIN&BIT(DIG_OUT1))//数据输入电平
#defineDB_INPUT2(SINPUT_PIN&BIT(DIG_OUT2))
voidInitDigCap(void)//初始化开关量采集
{CONTROL_DDR|=BIT(DIG_PL)+BIT(DIG_CLK)+BIT(DIG_CE1)+BIT(DIG_CE2);//置为输出
SINPUT_DDR&=~(BIT(DIG_OUT1)+BIT(DIG_OUT2)+);//置为输入
S_PL();
S_CE1();
S_CE2();
}
voidLockData(void)//锁定数据将数据全部锁入到寄存器中
{
S_PL();//高电平
Delay_Bus
(1);//延时一个总线周期
C_PL();//低电平
Delay_Bus
(1);//延时一个总线周期
S_PL();//高电平完成锁存
}
voidGetAllDigCap(void)//获取所有通道的开关量
{
unsignedchari,temp=0;
LockData();//锁定所有数据
C_CLK();
Delay_Bus
(1);
S_CLK();
//读取第一片里的数据
C_CE1();//使能片1
for(i=0;i<8;i++)
{
C_CLK();
Delay_Bus
(1);
S_CLK();//上升沿脉冲
Delay_Bus
(1);
if(DB_INPUT1)
{temp|=0x01;
temp<<=1;
}else
temp<<=1;
}
g_DigCap[0]=temp;
S_CE1();//关闭使能
(3)定时中断模块
voidInitTimer(void)//初始化计数器,使用Timer0产生1KHz的中断
{
TCCR0=0x00;
TCNT0=0x84;;
TCCR1B|=BIT(CS02);//64分频
TIMSK|=BIT(TOIE0);//timer0溢出中断开
}
ISR(TIMER0_OVF_vect)//Timer0溢出中断服务程序
{
TCNT0=0x84;
g_TimerFlag=1;//设置标志
}
(4)主程序:
intmain(void)
{
InitDevices();//初始化所有的设备
sei();//开总中断程序开始起跑
while
(1)//死循环
{if(g_TimerFlag==1)//如果时间标记为1
{GetAllDigCap();//获取所有开关量
TLC1543_GetAllValue();//获取所有模拟量
PutAllDataToBuf();//将所有数据送入发送缓冲区
if(g_RecFlag==0x78)//如果收到接收标志
{SendAllData();//发送所有数据
g_RecFlag=0;//置零
}
g_TimerFlag=0;//置零
}
}
}