智能避雨感光窗户系统模型设计——基于飞思卡尔MC9S12XS128
# 智能避雨感光窗户系统模型设计——基于飞思卡尔MC9S12XS128
一、效果展示
二、设计目的
介于现在许多家庭出于种种原因,家里的窗户在下雨或者是在白天不在家时都没有及时关闭,这样会带来很多不必要的麻烦,所以设计的这个系统,主要完成的任务是,能根据窗外的实时情况来调整窗户的开与关。这个模型结合MC9S12XS128中的周期中断定时器PIT、脉冲宽度调制器PWM、A-D转换器、串行通信接口SCI等基本模块,精确控制步进电机正转、反转来完成开窗、关窗动作。以此来巩固所学的知识,并应用于日常生活中。
当然这个也是我课程设计内容,做一些记录,给大家参考学习,如果有说的不对的,还望指正。
(福利推荐:阿里云、腾讯云、华为云服务器最新限时优惠活动,云服务器1核2G仅88元/年、2核4G仅698元/3年,点击这里立即抢购>>>)
三、设计思想
通过开启锁相环时钟,让总线时钟达到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转TTL | 2 |
下雨传感器 | 1 |
PC机 | 1 |
Android手机 | 1 |
面包板杜邦线 | 若干 |
五、智能避雨感光窗户模型功能框图
六、软件流程图
1、基本流程图
2、中断流程图
七、单片机定量分析
1、锁相环时钟
一般常用内部振荡的方式为MCU提供时钟源,振荡器时钟二分频后作为MCU内部总线时钟。MC9S12XS128通常外部采用16MHz石英晶体,即
$$ f_{BUSCLK}=f_{OSCCLK}/2 $$
根据分频因子、倍频分频因子、后分频因子有
$$ f_{REFCLK}=f_{OSCCLK}/left( REFDV+1 right) $$
$$ f_{VCOCLK}=2f_{OSCCLK}left( SYNR+1 right) /left( REFDV+1 right) $$
$$ f_{PLLCLK}=f_{VCOCLK}/left( 2times POSTDIV right) $$
开启锁相环时钟,并设置为系统时钟,则此时系统总线时钟有
$$ f_{BUSCLK}=f_{PLLCLK}/2 $$
$$ begin{cases} > REFDV=7\ > SYNR=19\ > POSTDIV=0\ >end{cases} $$
则此时,总线时钟为
$$ f_{BUSCLK}=f_{PLLCLK}/2=f_{VOCCLK}/2 \ =2f_{OSCCLK}left( SYNR+1 right) /left( REFDV+1 right) /2 \ =2times 16MHztimes left( 19+1 right) /left( 7+1 right) /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_Busclk,则该通道的定时周期为
$$ text{定时周期}=left( M+1 right) left( N+1 right) /f_{BUSCLK} $$
通过操作PIT模块相关寄存器,设定定时器通道0、1定时周期分别为1ms,100ms,定时器通道0使用微计数器0,定时器通道1使用微计数器1,即
$$ left( M_0+1 right) left( N_0+1 right) =1times 10^{-3}times 40times 10^6=40times 1000 $$
$$ left( M_1+1 right) left( N_1+1 right) =1times 10^{-1}times 40times 10^6=200times 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时钟源,
$$ text{时钟}A=text{总线时钟}/PCKA \ =40MHz/8=5MHz $$
$$ text{时钟}SA=text{时钟}A/left( 2times PWMSCLA right) \ =5MHz/left( 2times 5 right) =0.1MHz $$
PWM采用左对齐模式输出,输出电平先低后高,则有
$$ PWM01text{周期}=SAtext{时钟周期}times PWMPER01 \ =frac{1}{0.5MHz}times 500=frac{500}{500K}=1ms $$
$$ text{占空比}=left( PWMPER01-PWMDTYN01 right) /PWMPER01times 100% \ =left( 500-250 right) /500times 100%=50% $$
4、A-D转换器
MC9S12XS128内置A-D转换模块,模拟输入通道16路,转换位数可选(8位/10位/12位),具有数据对齐方式,单次/连续转换,转换结果比较等多种转换方式。通过操作A-D相关寄存器,可以设置通道数、转化位数、结果存放方式、A-D转换时钟频率以及选择A-D转换模式,如单通道单次转换模式、多通道单次转换模式、单通道序列转换模式、多通道序列转换模式等。
在智能避雨感光窗户模型中,需要采集光敏电阻以及下雨传感器的模拟电位值,则可以通过A-D转换器,设置为8位精度,两通道连续采样转换。
ATDCTL1
BIt7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|
ETRIGSEL | SRES1 | SRES0 | SMP_DIS | ETRIGCH3 | ETRIGCH2 | ETRIGCH1 | ETRIGCH0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
设置ATDCTL=0x00
选择8位转换精度
ATDCTL2
BIt7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|
—— | AEFC | ICLKSSTP | ETRIGLE | ETRIGP | ETRIGE | ASCIE | ACMPIE |
0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
设置ATDCTL2=0x40
打开CFF快速清零、
ATDCTL3
BIt7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|
DMJ | S4C | S3C | S2C | S1C | FIFO | FRZ1 | FRZ0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
设置ATDCTL3=0x10
数据左对齐,non-FIFO,转换序列长度为2
ATDCTL4
BIt7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|
SMP2 | SMP1 | SMP0 | PRS4 | PRS3 | PRS2 | PRS1 | PRS0 |
0 | 0 | 1 | 1 | 0 | 0 | 1 | 0 |
设置ATDCTL4=0xE3
采样时间为24个ATD时钟周期,ATDCLK=40MHz/8=5MHz(总线时钟40MHz)
ATDCTL5
BIt7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|
—— | SC | SCAN | MULT | CD | CC | CB | CA |
0 | 0 | 1 | 1 | 0 | 0 | 1 | 0 |
设置ATDCTL5=0x32
连续转换,以AN02为起始的2个通道
5、SCI模块
允许数据发送时$left( SCIxCR2_mathrm{TE=}1 right)$,数据寄存器SCIDRH、SCIDRL中的数据通过内部数据总线,送到发送数据寄存器缓冲区,然后数据从发送数据寄存器缓冲区装入发送移位寄存器,TDRE置1,发送移位寄存器得到数据后,在它的低位装入0作为起始位,在最后一位装入1作为停止位,然后按设定的波特率依次传送,经TXD引脚输出出去,发送结束TC置1。发送逻辑自动设置发送数据寄存器缓冲区空(TDHE)和发送结束(TC)标志。
允许数据接收时$left(SCIxCR2_mathrm{RE=}1 right)$,SCI从RXD引脚接收数据,经缓冲后驱动数据恢复模块,数据恢复模块以波特率的16倍的频率进行高速采样,完成发现数据起始位、空闲线探测、噪声探测等工作,并将16次采样中的7、8、9或8、9、10位,按3取2的多数占优逻辑决定送入接收移位寄存器的每一位的值。接到停止位后,接收移位寄存器的数据(自动去掉起始位、停止位)转移到接收数据缓冲区,同时将接收数据寄存器缓冲区满标志(RDRF)置位。当接收数据寄存器缓冲区的数据未被取走,而数据移位寄存器又接收到下一数据时,就会发生溢出。此时,数据移位寄存器中的新数据将会丢失,状态寄存器中溢出标志(OR)置位。
当$IREN=0text{时,}SCItext{波特率}=text{内部总线时钟}/left( 16times SBRleft[ 12:0 right] right)$,则
$$ SBRleft[ 12:0 right] =frac{text{内部总线时钟}}{16times SCItext{波特率}}=frac{40MHz}{16times 9600}approx 260 $$
将HC-05蓝牙模块与MC9S12XS128的SCI0连接,如下图所示,
6、步进电机定量分析
PWM1通道输出脉冲周期1ms,调节TB6600步进电机驱动器拨码开关设定细分为200(200个脉冲电机转动一圈),假定电机连接的导轨的螺距为10mm(电机转动一圈窗户移动的距离),假设窗户宽度为1.20m,那么
$$ N_{step}=frac{L_{Win}}{l}=frac{1.2m}{10mm}=120 $$
因此,步进电机需要转动120圈才能完成一个开窗或关窗动作,PWM1通道需要输出脉冲$120times 200left( text{个} right)$。
本设计模型用到的电机是两相四线电机,与驱动器接线如下图所示,
由于 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”,停止发送采样值;
效果如下图
<img src="http://9i0i.com/pic.php?p=https://img-blog.csdnimg.cn/20210131141531207.png"/><img src="http://9i0i.com/pic.php?p=https://img-blog.csdnimg.cn/20210131141547170.png" />
用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:openn"); 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(); } }
你还在原价购买阿里云、腾讯云、华为云、天翼云产品?那就亏大啦!现在申请成为四大品牌云厂商VIP用户,可以3折优惠价购买云服务器等云产品,并且可享四大云服务商产品终身VIP优惠价,还等什么?赶紧点击下面对应链接免费申请VIP客户吧:
相关文章
- Jgit的使用笔记
- 利用Github Action实现Tornadofx/JavaFx打包
- 叹息!GitHub Trending 即将成为历史!
- 微软软了?开源社区讨论炸锅,GitHub CEO 亲自来答
- GitHub Trending 列表频现重复项,前后端都没去重?
- Photoshop Elements 2021版本软件安装教程(mac+windows全版本都有)
- (ps全版本)Photoshop 2020的安装与破解教程(mac+windows全版本都有)
- (ps全版本)Photoshop cc2018的安装与破解教程(mac+windows全版本,包括2023
- 环境搭建:Oracle GoldenGate 大数据迁移到 Redshift/Flat file/Flume/Kafka测试流程
- 每个开发人员都要掌握的:最小 Linux 基础课
- 来撸羊毛了!Windows 环境下 Hexo 博客搭建,并部署到 GitHub Pages
- 超实用!手把手入门 MongoDB:这些坑点请一定远离
- 【GitHub日报】22-10-09 zustand、neovim、webtorrent、express 等4款App今日上新
- 【GitHub日报】22-10-10 brew、minio、vite、seaweedfs、dbeaver 等8款App今日上新
- 【GitHub日报】22-10-11 cobra、grafana、vue、ToolJet、redwood 等13款App今日上新
- Photoshop 2018 下载及安装教程(mac+windows全版本都有,包括最新的2023)
- Photoshop 2017 下载及安装教程(mac+windows全版本都有,包括最新的2023)
- Photoshop 2020 下载及安装教程(mac+windows全版本都有,包括最新的2023)
- Photoshop 2023 资源免费下载(mac+windows全版本都有,包括最新的2023)
- 最新版本Photoshop CC2018软件安装教程(mac+windows全版本都有,包括2023