ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

智能避雨感光窗户系统模型设计——基于飞思卡尔MC9S12XS128

2021-01-31 15:59:07  阅读:186  来源: 互联网

标签:飞思 delayus void unsigned char 避雨 MC9S12XS128 array 时钟


智能避雨感光窗户系统模型设计——基于飞思卡尔MC9S12XS128

一、效果展示

成果
LCD显示效果

二、设计目的

介于现在许多家庭出于种种原因,家里的窗户在下雨或者是在白天不在家时都没有及时关闭,这样会带来很多不必要的麻烦,所以设计的这个系统,主要完成的任务是,能根据窗外的实时情况来调整窗户的开与关。这个模型结合MC9S12XS128中的周期中断定时器PIT、脉冲宽度调制器PWM、A-D转换器、串行通信接口SCI等基本模块,精确控制步进电机正转、反转来完成开窗、关窗动作。以此来巩固所学的知识,并应用于日常生活中。
当然这个也是我课程设计内容,做一些记录,给大家参考学习,如果有说的不对的,还望指正

三、设计思想

通过开启锁相环时钟,让总线时钟达到40MHz,使能PWM通道,用来输出占空比50%、周期1ms的脉冲,从而控制步进电机转动角度,开启PIT定时器模块,用来对PWM通道输出脉冲计数;使能ATD模块,AD的两个通道分别连接雨水传感器及光敏电阻,连续采样,获取电压值,将两个参量数值与所设定的阈值比较,来控制步进电机是否正转、反转;同时从DS18B20来获取当前的温度值,通过LCD12864液晶来刷新显示每个参数当前值以及窗户状态;使能SCI串行通信模块,连接HC-05蓝牙,通过PC机连接HC-05蓝牙或者手机自带的蓝牙,发送指令给MC9S12XS128,返回当前参数各个值。

四、设计条件

名称数量
MC9S12XS128单片机开发板1
DC24V-4A适配器(给步进电机驱动器供电)1
DC12V-1A适配器(开发板供电)1
TB6600步进电机驱动器1
42步进电机1
HC-05蓝牙模块2
USB转TTL2
下雨传感器1
PC机1
Android手机1
面包板\杜邦线若干

五、智能避雨感光窗户模型功能框图

功能框图

六、软件流程图

1、基本流程图

基本流程图

2、中断流程图

中断流程图

七、单片机定量分析

1、锁相环时钟

一般常用内部振荡的方式为MCU提供时钟源,振荡器时钟二分频后作为MCU内部总线时钟。MC9S12XS128通常外部采用16MHz石英晶体,即

f B U S C L K = f O S C C L K f_{BUSCLK}=f_{OSCCLK} fBUSCLK​=fOSCCLK​

根据分频因子、倍频分频因子、后分频因子有

f R E F C L K = f O S C C L K / ( R E F D V + 1 ) f_{REFCLK}=f_{OSCCLK}/\left( REFDV+1 \right) fREFCLK​=fOSCCLK​/(REFDV+1)
f V C O C L K = 2 f O S C C L K ( S Y N R + 1 ) / ( R E F D V + 1 ) f_{VCOCLK}=2f_{OSCCLK}\left( SYNR+1 \right) /\left( REFDV+1 \right) fVCOCLK​=2fOSCCLK​(SYNR+1)/(REFDV+1)
f P L L C L K = f V C O C L K / ( 2 × P O S T D I V ) f_{PLLCLK}=f_{VCOCLK}/\left( 2\times POSTDIV \right) fPLLCLK​=fVCOCLK​/(2×POSTDIV)

开启锁相环时钟,并设置为系统时钟,则此时系统总线时钟有

f B U S C L K = f P L L C L K / 2 f_{BUSCLK}=f_{PLLCLK}/2 fBUSCLK​=fPLLCLK​/2
{ R E F D V = 7 S Y N R = 19 P O S T D I V = 0 \begin{cases} REFDV=7\\ SYNR=19\\ POSTDIV=0\\ \end{cases} ⎩⎪⎨⎪⎧​REFDV=7SYNR=19POSTDIV=0​

则此时,总线时钟为

f B U S C L K = f P L L C L K / 2 = f V O C C L K / 2 = 2 f O S C C L K ( S Y N R + 1 ) / ( R E F D V + 1 ) / 2 = 2 × 16 M H z × ( 19 + 1 ) / ( 7 + 1 ) / 2 = 40 M H z f_{BUSCLK}=f_{PLLCLK}/2=f_{VOCCLK}/2 \\ =2f_{OSCCLK}\left( SYNR+1 \right) /\left( REFDV+1 \right) /2 \\ =2\times 16MHz\times \left( 19+1 \right) /\left( 7+1 \right) /2 \\ =40MHz fBUSCLK​=fPLLCLK​/2=fVOCCLK​/2=2fOSCCLK​(SYNR+1)/(REFDV+1)/2=2×16MHz×(19+1)/(7+1)/2=40MHz

2、PIT定时器模块

PIT模块为模-数递减计数器,通过设定其计数寄存器初值,每个总线时钟8位微计数器做一次减1操作,当8位微计数器自减为0时,触发被控端16位计数器一次减1操作,然后8位微计数器再次自减直至为0,并再次触发16位计数器做一次减1操作,以此类推,直至16位计数器自减为0产生溢出。如果允许该定时器溢出中断,可以产生相应的中断申请。通过对总线时钟进行计数可以实现PIT定时功能,以触发外围模块或唤醒周期性中断。
4路24位定时器/计数器,每路可以分别打开和关闭,均可产生超时中断,定时周期可为总线时钟的1~2倍。例如,某个定时器通道使用的8位微计数器和16位计数器对应的加载寄存器的值为M和N,MCU内部总线时钟频率为 f B U S C L K f_{BUSCLK} fBUSCLK​,则该通道的定时周期为

定时周期 = ( M + 1 ) ( N + 1 ) / f B U S C L K \text{定时周期}=\left( M+1 \right) \left( N+1 \right) /f_{BUSCLK} 定时周期=(M+1)(N+1)/fBUSCLK​

通过操作PIT模块相关寄存器,设定定时器通道0、1定时周期分别为1ms,100ms,定时器通道0使用微计数器0,定时器通道1使用微计数器1,即

( M 0 + 1 ) ( N 0 + 1 ) = 1 × 1 0 − 3 × 40 × 1 0 6 = 40 × 1000 \left( M_0+1 \right) \left( N_0+1 \right) =1\times 10^{-3}\times 40\times 10^6=40\times 1000 (M0​+1)(N0​+1)=1×10−3×40×106=40×1000
( M 1 + 1 ) ( N 1 + 1 ) = 1 × 1 0 − 1 × 40 × 1 0 6 = 200 × 20000 \left( M_1+1 \right) \left( N_1+1 \right) =1\times 10^{-1}\times 40\times 10^6=200\times 20000 (M1​+1)(N1​+1)=1×10−1×40×106=200×20000

3、脉冲宽度调制器PWM

MC9S12XS128内置的PWM模块包括8路具有可编程周期和占空比的PWM通道,亦可以通过设置变为4个16位PWM通道。每个PWM通道由独立运行的8位通道计数器、通道周期寄存器和占空比寄存器等组成。通过设置各寄存器的参数设置,确定PWM信号波形的输出周期和占空比,设置每个通道PWM输出波形的极性和对齐方式,从4个时钟源(A,B,SA,SB)为通道选择时钟源。
控制步进电机转动需要设置脉冲周期1ms,占空比为50%。PWM通道0、1级联,PWM通道使用SA时钟源,

时钟 A = 总线时钟 / P C K A = 40 M H z / 8 = 5 M H z \text{时钟}A=\text{总线时钟}/PCKA \\ =40MHz/8=5MHz 时钟A=总线时钟/PCKA=40MHz/8=5MHz
时钟 S A = 时钟 A / ( 2 × P W M S C L A ) = 5 M H z / ( 2 × 5 ) = 0.1 M H z \text{时钟}SA=\text{时钟}A/\left( 2\times PWMSCLA \right) \\ =5MHz/\left( 2\times 5 \right) =0.1MHz 时钟SA=时钟A/(2×PWMSCLA)=5MHz/(2×5)=0.1MHz

PWM采用左对齐模式输出,输出电平先低后高,则有

P W M 01 周期 = S A 时钟周期 × P W M P E R 01 = 1 0.5 M H z × 500 = 500 500 K = 1 m s             PWM01\text{周期}=SA\text{时钟周期}\times PWMPER01 \\ =\frac{1}{0.5MHz}\times 500=\frac{500}{500K}=1ms\ \ \ \ \ \ \ \ \ \ \ PWM01周期=SA时钟周期×PWMPER01=0.5MHz1​×500=500K500​=1ms           
占空比 = ( P W M P E R 01 − P W M D T Y N 01 ) / P W M P E R 01 × 100 % = ( 500 − 250 ) / 500 × 100 % = 50 % \text{占空比}=\left( PWMPER01-PWMDTYN01 \right) /PWMPER01\times 100\% \\ =\left( 500-250 \right) /500\times 100\%=50\% 占空比=(PWMPER01−PWMDTYN01)/PWMPER01×100%=(500−250)/500×100%=50%

4、A-D转换器

MC9S12XS128内置A-D转换模块,模拟输入通道16路,转换位数可选(8位/10位/12位),具有数据对齐方式,单次/连续转换,转换结果比较等多种转换方式。通过操作A-D相关寄存器,可以设置通道数、转化位数、结果存放方式、A-D转换时钟频率以及选择A-D转换模式,如单通道单次转换模式、多通道单次转换模式、单通道序列转换模式、多通道序列转换模式等。
在智能避雨感光窗户模型中,需要采集光敏电阻以及下雨传感器的模拟电位值,则可以通过A-D转换器,设置为8位精度,两通道连续采样转换。

ATDCTL1

BIt76543210
ETRIGSELSRES1SRES0SMP_DISETRIGCH3ETRIGCH2ETRIGCH1ETRIGCH0
00000000

设置ATDCTL=0x00
选择8位转换精度


ATDCTL2

BIt76543210
——AEFCICLKSSTPETRIGLEETRIGPETRIGEASCIEACMPIE
01000000

设置ATDCTL2=0x40
打开CFF快速清零、


ATDCTL3

BIt76543210
DMJS4CS3CS2CS1CFIFOFRZ1FRZ0
00000000

设置ATDCTL3=0x10
数据左对齐,non-FIFO,转换序列长度为2


ATDCTL4

BIt76543210
SMP2SMP1SMP0PRS4PRS3PRS2PRS1PRS0
00110010

设置ATDCTL4=0xE3
采样时间为24个ATD时钟周期,ATDCLK=40MHz/8=5MHz(总线时钟40MHz)


ATDCTL5

BIt76543210
——SCSCANMULTCDCCCBCA
00110010

设置ATDCTL5=0x32
连续转换,以AN02为起始的2个通道

5、SCI模块

允许数据发送时 ( S C I x C R 2 _ T E = 1 ) \left( SCIxCR2\_\mathrm{TE=}1 \right) (SCIxCR2_TE=1),数据寄存器SCIDRH、SCIDRL中的数据通过内部数据总线,送到发送数据寄存器缓冲区,然后数据从发送数据寄存器缓冲区装入发送移位寄存器,TDRE置1,发送移位寄存器得到数据后,在它的低位装入0作为起始位,在最后一位装入1作为停止位,然后按设定的波特率依次传送,经TXD引脚输出出去,发送结束TC置1。发送逻辑自动设置发送数据寄存器缓冲区空(TDHE)和发送结束(TC)标志。
允许数据接收时 ( S C I x C R 2 _ R E = 1 ) \left(SCIxCR2\_\mathrm{RE=}1 \right) (SCIxCR2_RE=1),SCI从RXD引脚接收数据,经缓冲后驱动数据恢复模块,数据恢复模块以波特率的16倍的频率进行高速采样,完成发现数据起始位、空闲线探测、噪声探测等工作,并将16次采样中的7、8、9或8、9、10位,按3取2的多数占优逻辑决定送入接收移位寄存器的每一位的值。接到停止位后,接收移位寄存器的数据(自动去掉起始位、停止位)转移到接收数据缓冲区,同时将接收数据寄存器缓冲区满标志(RDRF)置位。当接收数据寄存器缓冲区的数据未被取走,而数据移位寄存器又接收到下一数据时,就会发生溢出。此时,数据移位寄存器中的新数据将会丢失,状态寄存器中溢出标志(OR)置位。
当 I R E N = 0 时, S C I 波特率 = 内部总线时钟 / ( 16 × S B R [ 12 : 0 ] ) IREN=0\text{时,}SCI\text{波特率}=\text{内部总线时钟}/\left( 16\times SBR\left[ 12:0 \right] \right) IREN=0时,SCI波特率=内部总线时钟/(16×SBR[12:0]),则

S B R [ 12 : 0 ] = 内部总线时钟 16 × S C I 波特率 = 40 M H z 16 × 9600 ≈ 260 SBR\left[ 12:0 \right] =\frac{\text{内部总线时钟}}{16\times SCI\text{波特率}}=\frac{40MHz}{16\times 9600}\approx 260 SBR[12:0]=16×SCI波特率内部总线时钟​=16×960040MHz​≈260

将HC-05蓝牙模块与MC9S12XS128的SCI0连接,如下图所示,
串口通信

6、步进电机定量分析

PWM1通道输出脉冲周期1ms,调节TB6600步进电机驱动器拨码开关设定细分为200(200个脉冲电机转动一圈),假定电机连接的导轨的螺距为10mm(电机转动一圈窗户移动的距离),假设窗户宽度为1.20m,那么

N s t e p = L W i n l = 1.2 m 10 m m = 120 N_{step}=\frac{L_{Win}}{l}=\frac{1.2m}{10mm}=120 Nstep​=lLWin​​=10mm1.2m​=120

因此,步进电机需要转动120圈才能完成一个开窗或关窗动作,PWM1通道需要输出脉冲 120 × 200 ( 个 ) 120\times 200\left( \text{个} \right) 120×200(个)。
本设计模型用到的电机是两相四线电机,与驱动器接线如下图所示,
步进电机与驱动器接线图
由于 MC9S12XS128的IO口驱动能力弱,与步进电机驱动器的控制端不能采用共阴极接法,需要采用共阳极接法,示意图如硬件原理图所示。(如果采用共阴极接法,电机始终未动

八、设计结果验证

1、两个AD采样值逻辑判断

下雨传感器板上干燥,遮住光敏电阻,其阻值迅速减小,并且小于所设定的阈值,当窗户初始状态为:打开 时,电机开始顺时针转动,LCD12864液晶状态显示:活动,当电机转动圈数达到120圈,电机停止转动,LCD12864液晶状态显示:关闭
光敏电阻曝光条件下,在下雨传感器板上,适量滴加清水,当窗户初始状态为:打开 时,观察LCD12864液晶,其AD采样值迅速减小,同时LCD12864液晶状态显示:活动,电机开始顺时针转动,当电机转动圈数达到120圈,电机停止转动, 状态显示:关闭
遮住光敏电阻,同时在下雨传感器板上适量滴加清水,当窗户初始状态为:打开 时,电机开始顺时针转动,当电机转动圈数达到120圈,电机停止转动,LCD12864液晶状态显示:关闭
光敏电阻曝光条件下,同时下雨传感器板上干燥,当窗户初始状态为:关闭 时,电机开始逆时针转动,当电机转动圈数达到120圈,电机停止转动,LCD12864液晶状态显示:打开

2、串口通信SCI

打开手机蓝牙,搜索关键词HC-05配对,打开手机蓝牙调试助手APP(手机软件商城搜蓝牙调试助手),
发送指令'O',MC9S12XS128返回 “command:open”,发送一次当前单片机三个采样值;
发送指令'A',MC9S12XS128返回“command:Auto_model”,每间隔1s发送当前单片机三个采样值;
发送指令'C',MC9S12XS128返回“command:close”,停止发送采样值;
效果如下图

用USB转TLL将 主机连接至PC机,另一个HC-05从机连接至 建立通信,发送如手机蓝牙调试助手指令,返回相同结果。如下图所示,


九、设计源代码

/*
 * 外部晶振16MHz,开启锁相环时钟,内部总线时钟为40MHz
 **/
#include <hidef.h>
#include "derivative.h"
/*定义步进电机控制端口*/   
#define step_DIR    PORTB_PB0
#define step_DIRDDR DDRB_DDRB0
#define step_Buffer PWME_PWME1
#define win_ON     1
#define win_OFF    0
#define step_ON    1
#define step_OFF   0
#define step_cycle 200    //定义步进电机细分每step_cycle个脉冲
#define win_ALL    100      
/*定义下雨湿度检测端口*/
#define Rain_value 2000
/*定义温度检测端口*/
#define  DSO       PTJ_PTJ1
#define  DSI       PTIJ_PTIJ1
#define  DSDDR     DDRJ_DDRJ1
/*定义光敏传感端口*/
#define  Light_value 2000
/*定义LCD12864显示屏*/
#define SCL        PTJ_PTJ7         //IIC的时钟线
#define SDA        PTJ_PTJ6         //IIC的数据线
#define CS         PTM_PTM2         //片选信号
#define SCL_dir    DDRJ_DDRJ7
#define SDA_dir    DDRJ_DDRJ6
#define CS_dir     DDRM_DDRM2
#define PSB        PTM_PTM3
#define PSB_dir    DDRM_DDRM3

char flag_1s=0,flag_over=0,flag_state=0;
unsigned char flag_win,flag_auto;
unsigned int counter0=0,counter1=0,cycle=0;
unsigned int Temperature,AD_Rain,AD_Light;
unsigned int zhengshu,xiaoshu;


char *symbols[5]={"窗户状态","湿度:","光照:","室温:"}; 
char *win_state[4]={"*","打开","关闭","活动"};
char Rain_array[7]={'0','.','0','-','0','0','%'};
char Light_array[7]={'0','.','0','-','0','0','%'};
char Temp_array[6]={'0','0','0','.','0','0'};
/**
 * @brief   延时函数1(延时时间=(countert*3)ms)
 * @param   countert 延时时间长短设置
 * @retval  无
 */
void delay3ms(unsigned int countert)
{
	unsigned int i,j;
	for(i=0;i<countert;i++)
		for(j=0;j<20000;)j++;
}
/**
 * @brief   延时函数2(延时时间近似= s us)
 * @param   s 延时时间长短设置
 * @retval  无
 */
void delayus(unsigned int s) 
{
    unsigned int m,n;
    for(m=0;m<s;m++) 
		for(n=0;n<7;)n++;
}
/**
 * @brief    PLL锁相环初始化函数(外部晶振16MHz,锁相环时钟80MHz,总线时钟40MHz)
 * @param    无 
 * @retval   无
 */
void PLL_init(void)
{
	SYNR=0X53;
	REFDV=0X07;
	while(CRGFLG_LOCK==0);  //时钟校正同步
	CLKSEL_PLLSEL=1;        //PLL时钟选择为系统时钟
}
/**
 * @brief    步进电机控制端口初始化函数
 * @param    无 
 * @retval   无
 */
 void step_init(void)
{
	step_DIRDDR=1;        //设置控制步进电机旋转方向的端口为输出
	step_DIR=win_OFF;
	step_Buffer=step_OFF; //停止转动电机	
}
/**
 * @brief    PWM初始化函数(PWM1输出脉冲,PWM7通道控制关闭PWM)
 * @param    无 
 * @retval   无
 */
void PWM_init(void)
{
	PWMCTL_CON01=1;   //通道0、1级联
	PWMPRCLK=0x03;    //时钟A的分频系数为8,fA=40/8=5MHz
	PWMSCLA=5;        //fSA=5/(2*5)=0.5MHz
	PWMCLK=0x02;      //通道PWM1使用SA时钟源
	PWMPER01=500;     //周期T=500/500K=1ms
	PWMDTY01=250;      //占空比50%
	PWMCAE=0x00;      //数据左对齐
	PWMPOL_PPOL1=0;   //输出电平先低后高
	PWME_PWME1=0;     //关闭通道PWM1
}
/*PWM中断服务函数*/
void interrupt 57 PWM(void)
{
	if(PWMSDN_PWM7IN==1)
		PWMSDN_PWMRSTRT=1;
		
}
/**
 * @brief    定时器PIT初始化函数(定时器通道0定时周期为1ms)
 * @param    无 
 * @retval   无
 */
void PIT_init(void)
{
	 PITCFLMT_PITE=0;  //关闭PIT模块
	 PITCE_PCE0=0;     //关闭定时器通道0
	 PITMUX_PMUX0=0;   //定时器通道0使用微计数器0
	 PITMTLD0=40-1;    //8位定时器初值
	 PITLD0=1000-1;    //16位定时器初值
	 PITINTE_PINTE0=1; //定时器通道0中断使能
	 PITCFLMT_PITE=1;  //使能PIT模块
}
/*PIT0中断服务函数,周期为1ms*/
void interrupt 66 PIT0(void)
{
	PITTF_PTF0=1;//清除标志位
	counter0++;
	if(counter0==step_cycle)
	{
		counter0=0;
		cycle++;
		if(cycle==win_ALL)//窗户完全打开或关闭
		{
			cycle=0;
		
			flag_over=1;
		}
	}
}
/**
 * @brief    A-D转换模块初始化函数(通道AN00、AN01连续采样)
 * @param    无 
 * @retval   无
 */
void ATD_init(void)
{
	ATD0CTL1=0X00;  //选择8位转换精度
	ATD0CTL2=0X40;  //打开CFF快速清零
	ATD0CTL3=0X10;  //数据左对齐,non-fifo,转换序列长度为2
	ATD0CTL4=0XE3;  //采样时间为24个ATD时钟周期,ATDCLK=8MHz/8=1MHz
	ATD0CTL5=0X32;  //连续转换,以AN00为起始的2个通道
}

/**
 * @brief    SCI模块初始化函数
 * @param    无 
 * @retval   无
 */
void SCI_init(void)
{
	SCI0BD=52;     //Fbusclk=8MHz,9600bps
	SCI0CR2=0x2c;  //允许发送,接收,允许接收中断
	
}
/**
 * @brief    串行通信发送函数
 * @param    c 需要发送到上位机的8位数据 
 * @retval   无
 */
void SCI0_SendChar(char c)
{
	while(SCI0SR1_TDRE==0);   //等待发送数据为空
	SCI0DRL=c;                //发送数据
}
/**
 * @brief    串行通信接收函数
 * @param    无 
 * @retval   返回从上位机接收的8位数据
 */
unsigned char SCI0_GetChar(void)
{
	while(SCI0SR1_RDRF==0);    
	return SCI0DRL; 
}
/**
 * @brief    串行通信发送字符串函数
 * @param    *putchar为数组或字符串 
 * @retval   无
 */
void send_string(char *putchar)
{
	while(*putchar!=0x00)  //判断字符串是否发送完成
	SCI0_SendChar(*putchar++);
}
/*SCI接收中断服务函数*/
void interrupt 20 SCI_recieve(void)
{
	unsigned char tempstr;
	if(SCI0SR1_RDRF==1)
	{
		tempstr=SCI0DRL;
		if(tempstr=='O')   //接收到指令'O'(Open)
		{
			flag_win=win_ON;//窗户标志位为打开
			flag_auto=0;
			send_string("command:open\n");
			if(PITCE_PCE0==0)
				send_string("Window is opening...");
			else send_string("window is working,Please wait");
		}
		if(tempstr=='C')   //接收到指令'C'(Close)
		{
			flag_win=win_OFF;//窗户标志位为关闭
			flag_auto=0;
			send_string("command:close \n");
			if(PITCE_PCE0==0)
				send_string("Window is closing...");
			else send_string("window is working,Please wait");
		}
		if(tempstr=='A')   //接收到指令'A'(auto)
		{
			flag_auto=1;   //窗户自动
			send_string("auto_model");
		}
	}
}

/**
 * @brief    初始化18B20函数
 * @param    无 
 * @retval   无
 */
void init_18B20(void)
{
 DSDDR=1;
 DSO = 1; 
 delayus(8);
 DSO = 0;          //拉低数据线,复位总线;
 delayus(504);     //延时504us 
 DSO = 1;         //提升数据线;
 delayus(32);     //延时32us;
 DSDDR=0;
 while(DSI)       //等待从器件器件应答信号;
 {delayus(1);}
 DSDDR=1;
 delayus(128);     //延时128us; 
 DSO = 1;          //提升数据线,准备数据传输;
}
/**
 * @brief    向18B20写入数据函数
 * @param    cmd 
 * @retval   无
 */
void WR18b20(byte cmd)
{
    unsigned char k;
    for(k=0;k<8;k++)
    {
        if(cmd & 0x01)        //低位在前;
        {
            DSO = 0;    
            delayus(8); 
            DSO = 1;          //发送数据;
        }                 
        else 
        {
            DSO = 0;          
            delayus(8);  
        }
        delayus(64);    //延时64us等待从器件采样;
        DSO = 1;        //拉高总线
        delayus(8);      
        cmd >>= 1;
    }
}
/**
 * @brief    由18B20读取数据
 * @param    无 
 * @retval   返回读取的数据
 */
unsigned char RD18b20(void)
{
    unsigned char k;
    unsigned char tmp=0;
    DSO = 1;  
    delayus(8);                       //准备读;
    for(k=0;k<8;k++)
    {
      tmp >>= 1;                       //先读取低位
      DSO = 0;                         //Read init;
      delayus(8);     
      DSO = 1;                         //必须写1,否则读出来的将是不预期的数据;
      delayus(3);                      //延时9us
      DSDDR=0;
      delayus(1);
      if(DSI)                          //在12us处读取数据;
      tmp |= 0x80;
      delayus(64);                     //延时64us
      DSDDR=1;
      DSO = 1;  
      delayus(8);                     //恢复One Wire Bus;
    }
    return tmp; 
}
/**
 * @brief    由18B20读取温度函数
 * @param    无 
 * @retval   返回温度值
 */
unsigned int read_T(void)
{
	unsigned int t;
	unsigned char temp[2];
	init_18B20();
	WR18b20(0xcc); //忽略ROM地址,直接向DS18B20发温度变换指令 
	WR18b20(0x44); //启动传感器进行温度转换,结果存入RAM
	init_18B20();
	WR18b20(0xcc); //忽略ROM地址,直接向DS18B20发温度变换指令
	WR18b20(0xbe); //读取RAM中9个字节的内容
	temp[0]=RD18b20();
	temp[1]=RD18b20();
	init_18B20();
	t=(temp[1]<<8)|temp[0];
	return(t); 
}
/**
 * @brief    LCD液晶接口初始化函数
 * @param    无 
 * @retval   无
 */
void INIT_PORT(void) 
{
	PSB_dir=1; //LCD控制端口设置为输出
	SCL_dir=1;
	SDA_dir=1;
	CS_dir=1;
	PSB=0;
	SCL=0;
	SDA=0;
	CS=0;
}
/**
 * @brief    IIC写一个字节的数据
 * @param    A需要写入的字节 
 * @retval   无
 */
void write_byte(unsigned char A) 
{ 
	unsigned char j; 
	for(j=0;j<8;j++)        
	{ 
		if((A<<j)&0x80)SDA=1; 
		else SDA=0; 
		SCL=1;
		delayus(3); 
		SCL=0;
		delayus(3); 
	} 
} 
/**
 * @brief    向液晶发送数据 
 * @param    C 需要发送给LCD的数据 
 * @retval   无
 */
void write_Data(unsigned char C)
{
	CS=1; 
	SCL=0; 
	write_byte(0xFA); 
	write_byte(C&0xF0);                 //写高四位数据 
	write_byte(0xf0&(C<<4));            //写低四位数据 
	CS=0; 
}
/**
 * @brief    向液晶发送指令 
 * @param    B 需要发送给LCD的指令 
 * @retval   无
 */
void write_command(unsigned char B) 
{ 
	CS=1; 
	SCL=0; 
	write_byte(0xF8); 
	write_byte(B&0xF0);             //写高四位数据 
	write_byte(0xf0&(B<<4));        //写低四位数据 
	CS=0; 
}
/**
 * @brief    LCD液晶清屏函数 
 * @param    无 
 * @retval   无
 */
void lcd_clear(void)
{
	write_command(0x30);//0011,0000 功能设置,一次送8位数据,基本指令集 
	delayus(80);       //延时80us
	write_command(0x03);//AC归0,不改变DDRAM内容 
	delay3ms(2);        //延时6ms
	write_command(0x01);//0000,0001 清DDRAM 
	delay3ms(2);        //延时6ms
	write_command(0x06);//写入时,游标右移动 
	delayus(80);       //延时80us
	write_command(0x0C);//0000,1100  整体显示,游标off,游标位置off
	delayus(80);       //延时80us
}


/**
 * @brief    向LCD液晶发送字符串
 * @param    row为写入数据所在的行数
 * @param    col为写入数据所在的列数
 * @param    *data1为写入的数据
 * @retval   无
 */
void lcd_string(unsigned char row,unsigned char col,char *data1,unsigned char *array)
{
	for(;row<4&&(*data1)!=0;row++)
	{ 
		for(;col<8&&(*data1)!=0;col++)
		{ 
			write_command(array[row*8+col]);
			delayus(80);       //延时80us
			write_Data(*data1++); 
			delayus(80);       //延时80us
			write_Data(*data1++); 
			delayus(80);       //延时80us
		}
		col=0;
	}
}
/**
 * @brief    LCD液晶显示函数 
 * @param    无 
 * @retval   无
 */
void LCD_Play(void)
{
	unsigned char i,j,k;
	delayus(40);
	write_command(0x94);  //第二行第四列开始
	delayus(80);
	for(i=0;i<7;i++)
	{
		write_Data(Rain_array[i]);
		delayus(80);
	}
	//lcd_string(1,6,Rain_array);

	write_command(0x8c);  //第三行第四列开始
	delayus(80);
	for(j=0;j<7;j++)
	{
		write_Data(Light_array[j]);
		delayus(80);
	}
	//lcd_string(2,6,Light_array);
	
	write_command(0x9c);  //第四行第四列开始
	delayus(80);
	for(k=0;k<6;k++)
	{
		write_Data(Temp_array[k]);
	}
	write_Data(0XA1);
	delayus(80);
	write_Data(0XE6);
	delayus(80);
	
	//lcd_string(3,6,Temp_array);
}
/**
 * @brief    主函数
 * @param    无 
 * @retval   无
 */
void main (void)
{
  unsigned char m;
	char* Symbols[4]={"窗户状态","湿度:","光照:","室温:"}; 
  char* Win_state[4]={"*","打开","关闭","活动"};
  unsigned char adress_table[]=                //定义液晶点阵的坐标
 { 
  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       //第四行汉字位置 
  };
  Rain_array[1]='.',Light_array[1]='.';
  Rain_array[3]='-',Light_array[3]='-';
  Rain_array[6]='%',Light_array[6]='%';
  Temp_array[3]='.';
  for(m=0;m<4;m++) 
  {
    symbols[m]=Symbols[m];
    win_state[m]=Win_state[m];
    
  }
	DisableInterrupts;              //关闭中断
	PLL_init();
	step_init();
	PIT_init();     
	init_18B20();
	PWM_init();
	ATD_init();
	INIT_PORT();
	SCI_init();
	EnableInterrupts;               //打开中断
	lcd_clear();                    //LCD清屏
	for(;;)
	{
			while(!(ATD0STAT0&0X80));   //查询ATD是否完成
			AD_Rain=(unsigned int)((unsigned long)ATD0DR0H*5000/255);//下雨检测传感器转换值
			Rain_array[0]=AD_Rain/1000+48;//0字符的ASCII码为48
			Rain_array[2]=(AD_Rain%1000)/100+48;
			Rain_array[4]=(AD_Rain/50)/10+48;
			Rain_array[5]=(AD_Rain/50)%10+48;
			AD_Light=(unsigned int)((unsigned long)ATD0DR1H*5000/255);//光敏电阻电位转换值
			Light_array[0]=AD_Light/1000+48;//0字符的ASCII码为48
			Light_array[2]=(AD_Light%1000)/100+48;
			Light_array[4]=(AD_Light/50)/10+48;
			Light_array[5]=(AD_Light/50)%10+48;
			Temperature=read_T();               //读取温度值
			if(Temperature<2001)                //温度为0上的温度
			{
				Temperature&=0x07ff;
				zhengshu=Temperature/16;              //计算温度的整数部分
				xiaoshu=(Temperature*25/4)%100;       //计算温度的小数部分
				Temp_array[0]=zhengshu/100+48;        //计算温度的各位的字符值
				Temp_array[1]=(zhengshu%100)/10+48;
				Temp_array[2]=zhengshu%10+48;
				Temp_array[4]=xiaoshu/10+48;
				Temp_array[5]=xiaoshu%10+48;
			}
			else                                 //温度为0下的温度
			{
				Temperature=~(Temperature-1);
				zhengshu=Temperature/16;         //计算温度的整数部分
				xiaoshu=(Temperature*25/4)%100;  //计算温度的小数部分
				Temp_array[0]='-';
				Temp_array[1]=zhengshu/10+48;    //计算温度的各位的字符值
				Temp_array[2]=zhengshu%10+48;
				Temp_array[4]=xiaoshu/10+48;
				Temp_array[5]=xiaoshu%10+48;
			}
      
    		//关窗信号(上位机发出关窗信号 或 下雨信号 或 光照降到指定程度以下)
		if((AD_Rain<Rain_value)||(AD_Light>Light_value))
		{
			if((step_DIR==win_ON)&&(PITCE_PCE0==0))
			{
				step_DIR=win_OFF;
				step_Buffer=step_ON;//打开通道PWM1,输出脉冲
				PITCE_PCE0=1;       //打开定时器通道0,开始计算脉冲个数
			}
		}
		//开窗信号 (无下雨且光照升到指定程度以上 或 上位机发出开窗信号)
		if((AD_Rain>=Rain_value)&&(AD_Light<=Light_value))
		{
			if((step_DIR==win_OFF)&&(PITCE_PCE0==0))
			{
				step_DIR=win_ON;
				step_Buffer=step_ON;//打开通道PWM1,输出脉冲
				PITCE_PCE0=1;       //打开定时器通道0,开始计算脉冲个数
			}
		}
		if(flag_over==1)//判断是否开窗或关窗完成
		{
			flag_over=0;
			step_Buffer=step_OFF;//关闭通道PWM1
			PITCE_PCE0=0;        //关闭定时器通道0,停止对脉冲计数
		}
		if(PITCE_PCE0==0)
		{
			switch(step_DIR)
			{
				case win_ON:flag_state=1;break;
				case win_OFF:flag_state=2;break;
			}
		} else flag_state=3;
	  delay3ms(100);
		lcd_clear();
		lcd_string(0,0,symbols[0],adress_table);
		lcd_string(0,5,win_state[flag_state],adress_table);
		lcd_string(1,1,symbols[1],adress_table);
		lcd_string(2,1,symbols[2],adress_table);
		lcd_string(3,1,symbols[3],adress_table);
		LCD_Play();
	}
}

十、附录

  1. 使用的主要调试软件:Freescale Codewarrior
    安装包链接:https://pan.baidu.com/s/1GcY2LUZwmdh_gvv0MJgbRQ 提取码:5feq
  2. MC9S12XS128开发板原理图 链接:https://pan.baidu.com/s/1xm8xNXYYEVljkw15pjfhfw 提取码:9lbw
  3. 模型设计简易原理图,(可以在开发板芯片周围焊上排针,方便接杜邦线)链接:https://pan.baidu.com/s/1T8k81P6NCby7Cig9wLY0pg 提取码:ct0k
  4. 本次课程设计报告word文档
    https://download.csdn.net/download/qq_44946715/14976311

十一、参考文献

  1. MC9S12单片机原理及嵌入式应用开发技术 第二版 陈万忠 主编
  2. 两个HC05蓝牙模块相互之间的通信
  3. HC05蓝牙模块配对步骤及AT模式设置方法
  4. 51单片机DS18B20温度传感器的初始化、读写函数的编写
  5. 51单片机控制TB6600驱动器驱动42步进电机
  6. 一种提高单片机i/o口驱动能力的方法
  7. 步进电机之步进电机驱动器使用说明
  8. 步进驱动器简单接线说明书

标签:飞思,delayus,void,unsigned,char,避雨,MC9S12XS128,array,时钟
来源: https://blog.csdn.net/qq_44946715/article/details/113458003

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有