首页 > 其他 > 详细

单片机课程设计——温控系统

时间:2019-06-12 23:26:46      阅读:199      评论:0      收藏:0      [点我收藏+]

2019-06-12 22:51:39


期末的课程设计告一段落,复习进度变慢,得赶紧进入状态!

总结一下设计中遇到的问题:

 

技术分享图片

 技术分享图片

技术分享图片

技术分享图片

1、硬件设计

技术分享图片

2、软件设计

总体结构图

技术分享图片

代码:

1、Main.c

  1 #include <reg52.h>
  2 #include<LCD1602.h>
  3 #include<stdio.h>
  4 #include<DS18B20.h>
  5 #include<Button.h>
  6 #include<chuankou.h>
  7 #include<fengshan.h>
  8 
  9 void display_all();//温度显示
 10 sbit BEEP=P3^2;
 11 
 12 uint flag_n=0;//用于获取正确的温度0表示还未获取,1表示已经获取
 13 
 14       
 15 
 16 void delayms(uchar i)
 17 {
 18     while(i--);
 19 }
 20 
 21 /*******************************************************************/      
 22 /*                                                                                                                                 
 23 /*                         主函数                                    
 24 /*                                                                         
 25 /*******************************************************************/ 
 26 
 27 void main()
 28 {      uchar i;
 29 
 30     Init_inter();
 31     lcd_init();                 //LCD初始化
 32     delay(10);
 33 
 34     i = 0;
 35     lcd_wcmd(0x80);             //第1行第1列
 36 
 37     while(table2[i] != \0) //按键1对应的字样
 38        {                             
 39            lcd_wdata(table2[i]);
 40            i++;           
 41     }
 42     
 43     
 44     lcd_wcmd(0x80+0x0d);     // 设置显示位置为第二行第13个字符
 45     lcd_wdata(0xdf);         // 显示字符°
 46     lcd_wdata(c);
 47     
 48     i=0;
 49 
 50     lcd_wcmd(0x80+0x40);
 51     while(table4[i] != \0) //按键1对应的字样
 52     {                             
 53            lcd_wdata(table4[i]);
 54            i++;           
 55     }
 56 
 57     Dis_temp(warn_h);
 58     i=0;
 59     lcd_wcmd(0x80+0x46);
 60     while(table5[i] != \0) //按键1对应的字样
 61     {                             
 62            lcd_wdata(table5[i]);
 63            i++;           
 64     }
 65     
 66     Dis_temp(warn_l);
 67     
 68           
 69 
 70     delayms(5);
 71     while(1)
 72      {
 73         
 74 
 75           keyscan();
 76         flag_n++;
 77         if(flag_n>1000) flag_n=3;
 78 
 79         tempchange();//实时获取温度    
 80         temp=get_temp();    //获取温度的变化是有一定的延时的
 81         if(flag_n>68){    //使用flag_n变量的原因:当第一次获取实时温度时,有一定的延时。当代码烧录进去时会出现85这个温度,因此为了解决这个问题引入flag_n变量,让它第一次获取温度时晚点显示在LCD屏幕上
 82         
 83             display_all();//将数据显示在LCD1602上
 84             
 85             sprintf(MESSAGE,"%d",temp);
 86             MESSAGE[3]=MESSAGE[2];
 87             MESSAGE[2]=.;
 88             MESSAGE[4]=\0;
 89           
 90 
 91             comm();
 92         
 93             if(temp>=warn_h*10||temp<=warn_l*10) //当实时温度不在设定的范围内时,蜂鸣器响
 94             {    
 95                BEEP=1;    delayms(1000);
 96                       
 97             
 98                BEEP=0;    delayms(1000);
 99     
100             
101         
102             } 
103         
104         }
105                                                                                                                        
106 
107                     
108      }
109 }
 1 sbit KEY1=P1^0;//调高TH
 2 sbit KEY2=P1^1;//调低TH
 3 sbit KEY3=P1^2;//调高TL
 4 sbit KEY4=P1^3;//调低TL
 5 /********注意:这一段代码文件名字为BUTTON.H************/
 6 uchar flag=0;
 7 
 8 uchar k=0;
 9 
10 uchar key_state=0;
11 
12 void delay_system(unsigned int n)       //延时函数                       
13 { 
14     uint x,y;  
15     for(x=n;x>0;x--) 
16         for(y=110;y>0;y--); 
17 } 
18 void  keyscan(void)
19 {
20     if(KEY1==0)
21     {
22         delay_system(1);
23         if(KEY1==0){
24             warn_h++;
25             while(!KEY1);//等待按键释放
26         }
27     }
28     if(KEY2==0)
29     {
30         delay_system(1);
31         if(KEY2==0){
32             warn_h--;
33             while(!KEY2);//等待按键释放
34         }
35     }
36     if(KEY3==0)
37     {
38         delay_system(1);
39         if(KEY3==0){
40             warn_l++;
41             while(!KEY3);//等待按键释放
42         }
43     }
44     if(KEY4==0)
45     {
46         delay_system(1);
47         if(KEY4==0){
48             warn_l--;
49             while(!KEY4);//等待按键释放
50         }
51     }
52 }
53 
54 void Init_inter()
55 {
56     TMOD=0x01;      //使用定时器T0的模式1
57   EA=1;           //开总中断
58   ET0=1;          //定时器T0中断允许
59   TR0=1;          //启动定时器T0 
60     TH0=(65536-1000)/256;    //定时器T0赋初值,每计数200次(217微秒)发送一次中断请求
61     TL0=(65536-1000)%256;    //定时器T0赋初值
62 
63 }
64 
65 /*************************************************
66 函数功能:定时器T0的中断服务子程序
67 **************************************************/
68 void Time0_serve(void) interrupt 1  
69 {
70 
71     TH0=(65536-1000)/256;
72     TL0=(65536-1000)%256;
73     
74 }
  1 /*******************************************************************/      
  2 /*                                                                                                                                 
  3 /*                  DS18B20温度传感器模块                                    
  4 /*                                                                         
  5 /*******************************************************************/
  6 sbit ds = P3^7;        // 温度传感器信号线
  7 /********注意这一段代码文件名为DS18B20.H************/
  8 
  9 void dsreset(void)    //18B20复位,初始化函数
 10 {
 11   uint i;
 12   ds=0;
 13   i=103;
 14   while(i>0)i--;
 15   ds=1;
 16   i=4;
 17   while(i>0)i--;
 18 }
 19 
 20 bit tempreadbit()   //读1位数据函数
 21 {
 22    uint i;
 23    bit dat;
 24    ds=0;i++;          //i++ 起延时作用
 25    ds=1;i++;i++;
 26    dat=ds;
 27    i=8;while(i>0)i--;
 28    return dat;
 29 }
 30 
 31 uchar tempread()   //读1个字节
 32 {
 33   uchar i,j,dat;
 34   dat=0;
 35   for(i=1;i<=8;i++)
 36   {
 37     j=tempreadbit();
 38     dat=(j<<7)|(dat>>1);   //读出的数据最低位在最前面,这样刚好一个字节在DAT里
 39   }
 40   return dat;
 41 }
 42 
 43 void tempwritebyte(uchar dat)   //向DS18B20写一个字节数据函数
 44 {
 45   uint i;
 46   uchar j;
 47   bit testb;
 48   for(j=1;j<=8;j++)
 49   {
 50     testb=dat&0x01;
 51     dat=dat>>1;
 52     if(testb)     //写 1
 53     {
 54       ds=0;
 55       i++;i++;
 56       ds=1;
 57       i=8;while(i>0)i--;
 58     }
 59     else
 60     {
 61       ds=0;       //写 0
 62       i=8;while(i>0)i--;
 63       ds=1;
 64       i++;i++;
 65     }
 66 
 67   }
 68 }
 69 void tempchange(void)   //DS18B20 开始获取温度并转换
 70 {
 71   dsreset();
 72   delay(1);
 73   tempwritebyte(0xcc);  // 写跳过读ROM指令
 74   tempwritebyte(0x44);  // 写温度转换指令
 75 }
 76 uint get_temp()         //读取寄存器中存储的温度数据函数
 77 {
 78    uchar a,b;
 79 
 80   dsreset();
 81   delay(1);
 82   tempwritebyte(0xcc);
 83   tempwritebyte(0xbe);
 84   a=tempread();         //读低8位
 85   b=tempread();         //读高8位
 86   temp=b;
 87   temp<<=8;            //两个字节组合为1个字
 88   temp=temp|a;
 89   f_temp=temp*0.0625;      //温度在寄存器中为12位 分辨率位0.0625°
 90   temp=f_temp*10+0.5; //乘以10表示小数点后面只取1位,加0.5是四舍五入
 91   f_temp=f_temp+0.05; 
 92   return temp;         //temp是整型
 93 }
 94 
 95 void display_all()
 96 {
 97         /*一下为温度显示模块*/
 98     
 99         unsigned char i; 
100     
101         lcd_wcmd(0x80+0x09);
102         
103 
104     
105         t[0]=temp/100; //百位
106         t[1]=temp%100/10; //十位
107         t[2]=temp%10;    //个位(小数点后面的一位)
108     
109 
110         lcd_wdata(table3[t[0]]);       //温度的十位
111         lcd_wdata(table3[t[1]]);  //温度的个位
112         lcd_wdata(0x20+14);    //小数点
113         lcd_wdata(table3[t[2]]);
114             
115         i=0;
116 
117         lcd_wcmd(0x80+0x40);
118         while(table4[i] != \0) //按键1对应的字样
119         {                             
120                lcd_wdata(table4[i]);
121                i++;           
122         }
123     
124         Dis_temp(warn_h);
125         i=0;
126         lcd_wcmd(0x80+0x46);
127         while(table5[i] != \0) //按键1对应的字样
128         {                             
129                lcd_wdata(table5[i]);
130                i++;           
131         }
132         
133         Dis_temp(warn_l);
134     
135 }
 1 /*******************************************************************/      
 2 /*                                                                                                                                 
 3 /*                      1602液晶模块     这一段代码文件名字为LCD1602.H                               
 4 /*                                                                         
 5 /*******************************************************************/                                                                                                        
 6 sbit LCD_RS = P2^6;    // 数据/命令选择端(H/L)         
 7 sbit LCD_RW = P2^5;       // 读写选择端(1/0)
 8 sbit LCD_EP = P2^7;       // 使能信号
 9 #define uchar unsigned char 
10 #define uint unsigned int 
11 uchar code table2[] = {"Now temp:   "};
12 uchar code table3[] = {"0123456789"};
13 uchar code table4[]="TH:";
14 uchar code table5[]="TL:";
15 uchar t[4];    //存温度的每一位
16 uint temp=0;
17 float f_temp=0;
18 uint warn_h=27;//初始的上限为30
19 uint warn_l=15;//初始下限为15
20 void delay(uint xms)
21 {                           // 延时函数
22     uint i,j;
23     for(i = xms;i > 0;i--)
24         for(j = 110;j > 0;j--);
25 }    
26 void lcd_wcmd(uchar cmd)   // 写入指令数据到LCD
27 {                          //RS=L,RW=L,E=高脉冲,D0-D7=指令码。
28     LCD_RS = 0;
29     LCD_RW = 0;
30     LCD_EP = 0; 
31     P0 = cmd;
32     delay(1);
33     LCD_EP = 1;
34     delay(1);
35     LCD_EP = 0;  
36 }  
37 void lcd_wdata(uchar dat)  //写入字符显示数据到LCD
38 {                          //RS=H,RW=L,E=高脉冲,D0-D7=数据
39     LCD_RS = 1;
40     LCD_RW = 0;
41     LCD_EP = 0;
42     P0 = dat;
43     delay(1);
44     LCD_EP = 1;
45     delay(1);
46     LCD_EP = 0; 
47 }
48 void lcd_init()              //LCD初始化设定初始化函数
49 {                        
50     lcd_wcmd(0x38);       //16*2显示,5*7点阵,8位数据
51     delay(1);             
52     lcd_wcmd(0x0c);       //设置开显示,不显示光标
53     delay(1);
54     lcd_wcmd(0x06);       //写一个字符后地址指针加1
55     delay(1);
56     lcd_wcmd(0x01);       //显示清0,数据指针清0
57     delay(1);
58 }
59 
60 /*void Dis_temp(uint t);//用于设置上下限显示*/
61 void Dis_temp(uint t){
62     
63     lcd_wdata(table3[t/10]);
64     lcd_wdata(table3[t%10]);
65 }
 1 #define key P1     
 2 void delay2(uchar n);
 3 void delaym(unsigned int i);
 4 char  MESSAGE[5]="234"; 
 5 /*****注意这一段代码文件名字为CHUANKOU.H**********/
 6 unsigned char a; 
 7 unsigned char UART_buff;
 8 unsigned char th[]="12H";
 9 unsigned char i=0;
10 unsigned char change=0;
11 void delay2(uchar n)
12 {
13     uchar i,j;
14     for(i=0;i<n;i++)
15         for(j=0;j<50;j++);
16 }
17 /********发送***********/
18 void post()     //发送
19 { 
20      
21          a=0; 
22         
23         while(MESSAGE[a] != \0) { 
24             
25              SBUF = MESSAGE[a]; 
26             while(!TI); // 等特数据传送 (TI 发送中断标志) 
27             TI = 0; // 清除数据传送标志 
28             a++; // 下一个字符 
29         } 
30 
31     
32 }
33 
34 
35 void comm()
36 {
37     
38     SCON = 0x50; //REN=1 允许串行接受状态,串口工作模式1
39     TMOD|= 0x20; //定时器工作方式2
40     PCON|= 0x80;
41     TH1 = 0xF3; //baud*2 /* 波特率4800、数据位8、停止位1。校验位无 (12M)
42     TL1 = 0xF3;
43     TR1 = 1;
44     ES = 1; //开串口中断
45     EA = 1; // 开总中断
46     EX0=1;    
47     post();
48     
49     
50 }
51 void delaym(unsigned int i) //延时处理程序 
52 { 
53      unsigned char j; 
54      for(i; i > 0; i--) 
55      for(j = 200; j > 0; j--) ;
56 }
57 
58 void  ser_int  (void)  interrupt  4  
59 {
60   if(RI  ==  1)  {    //如果收到.
61      
62       RI  =  0;      //清除标志.
63       UART_buff  =  SBUF;    //接收.
64       th[i]=UART_buff ;
65       i++;
66       if(i==3){
67           i=0;
68           change=1;
69       }
70   }
71   
72      if(change){       //在上位机中,为了让下位机能分别出上下限于是结尾用H表示上限,L表示下限
73         if(th[2]==H)
74             warn_h=(th[0]-0)*10+(th[1]-0);
75         else
76             warn_l=(th[0]-0)*10+(th[1]-0);
77         change=0;    
78     }  
79 }  
  1 Dim s1(60)   ‘上位机代码
  2 Dim sum1 As Double
  3 Dim flag As Integer
  4 Private Declare Function Beep Lib "kernel32" (ByVal dwFreq As Long, ByVal dwDuration As Long) As Long
  5 
  6 
  7 Private Sub Command1_Click()
  8 If Text1.Text = "" Then
  9     MsgBox ("端口未打开!")
 10 Else
 11     Picture1.Cls
 12     Timer4.Enabled = True
 13     
 14     Picture1.Line (-2, 0)-(68, 0)
 15     Picture1.Line (0, 38)-(0, -2)
 16     Picture1.CurrentX = -2: Picture1.CurrentY = 0: Picture1.Print 0
 17     Picture1.CurrentX = 63: Picture1.CurrentY = 0: Picture1.Print "时间/S"
 18     Picture1.CurrentX = 0.2: Picture1.CurrentY = 38: Picture1.Print "温度/℃"
 19     
 20     For i = 1 To 12
 21        Picture1.Line (0, i * 3)-(60, i * 3), RGB(180, 180, 180)
 22     Next i
 23     
 24       For i = 1 To 20
 25         Picture1.Line (i * 3, 0)-(i * 3, 36), RGB(180, 180, 180)
 26         Picture1.CurrentX = i * 3 - 1.2: Picture1.CurrentY = 0: Picture1.Print i * 3
 27       Next i
 28     
 29     
 30     For j = 1 To 12
 31       Picture1.CurrentX = -2.7: Picture1.CurrentY = j * 3 + 1: Picture1.Print j * 3
 32     Next j
 33 
 34 End If
 35 End Sub
 36 
 37 Private Sub Command2_Click()
 38 If Text1.Text = "" Then
 39 MsgBox ("端口暂时未接收到数据!请检查端口是否打开!")
 40 
 41 Timer3.Enabled = True
 42 
 43 End If
 44 End Sub
 45 
 46 Private Sub Command3_Click()
 47 MSComm1.PortOpen = True
 48 Timer1.Enabled = True
 49 Label13.Caption = "端口通信中"
 50 Shape5.FillColor = RGB(0, 255, 0)
 51 Shape2.FillColor = RGB(0, 255, 0)
 52 
 53 Timer1.Enabled = True
 54 End Sub
 55 
 56 Private Sub Command4_Click()
 57 End
 58 Unload Me
 59 End Sub
 60 
 61 Private Sub Command5_Click()
 62 MSComm1.PortOpen = False
 63 Shape5.FillColor = RGB(0, 0, 0)
 64 Shape2.FillColor = RGB(0, 0, 0)
 65 Timer1.Enabled = False
 66 Timer4.Enabled = False
 67 Label13.Caption = "端口关闭"
 68 Text1.Text = ""
 69 
 70 End Sub
 71 
 72 Private Sub Command6_Click() 写文件函数
 73 
 74 
 75 Timer3.Enabled = False
 76 s = "D:\温度记录\text1.txt"
 77 Open "D:\温度记录\text1.txt" For Append As #1
 78 Print #1, Format(Now, "AMPM(hh:mm:ss)") & "    " & Text1.Text
 79 Close #1
 80 MsgBox ("历史温度已经保存在" & s & "下,请注意查看!")
 81 
 82 End Sub
 83 
 84 Private Sub Command7_Click()
 85 If Text1.Text = "" Then
 86     MsgBox ("端口未打开!")
 87 Else
 88     Timer4.Enabled = False
 89 End If
 90 End Sub
 91 
 92 Private Sub Command8_Click() 点击发送上限按钮触发事件
 93 If Text1.Text = "" Then
 94     MsgBox ("端口未打开!")
 95 Else
 96  MSComm1.InputMode = 0 设置文本格式
 97  MSComm1.Output = Text6.Text + "H" 上限值传送
 98 End If
 99 End Sub
100 
101 Private Sub Command9_Click() 点击发送下限按钮触发事件
102 If Text1.Text = "" Then
103     MsgBox ("端口未打开!")
104 Else
105  MSComm1.InputMode = 0 设置文本格式
106  MSComm1.Output = Text7.Text + "L"   下限值传送
107 End If
108 End Sub
109 
110 Private Sub Dir1_Change() 文件驱动
111 File1.Path = Dir1.Path
112 File1.Pattern = "*.txt"
113 End Sub
114 文件模块
115 Private Sub Drive1_Change()
116 Dir1.Path = Drive1.Drive
117 End Sub
118 
119 Private Sub File1_DblClick()  鼠标双击事件(打开指定文件)函数
120 Text4.Text = ""
121 p = File1.Path & "\" & File1.FileName
122 Picture1.Picture = Loadpicture(p)
123 Text4.Text = LoadFile(p)
124 
125 Open p For Input As #1  读方式打开文件
126  Do While Not EOF(1)   循环,只到文件结束
127      Line Input #1, Data 将"*.txt"中的一行读到data 中
128     Text1.Text = Text1.Text + Data
129     Text4.Text = Text4.Text & Data & Chr(13) & Chr(10)
130  Loop
131 Close #1   关闭文件号
132 End Sub
133 Private Sub Form_Load()   端口初始化函数
134 MSComm1.Settings = "4800,n,8,1"
135 MSComm1.CommPort = 4
136 MSComm1.InputLen = 0
137 MSComm1.InBufferSize = 512
138 MSComm1.InBufferCount = 0
139 MSComm1.OutBufferSize = 512
140 MSComm1.OutBufferCount = 0
141 MSComm1.RThreshold = 1
142 MSComm1.SThreshold = 1
143 flag = 0
144 MSComm1.PortOpen = True
145 Timer1.Enabled = False
146 
147 
148 Picture1.Line (-2, 0)-(68, 0)
149 Picture1.Line (0, 38)-(0, -2)
150 Picture1.CurrentX = -2: Picture1.CurrentY = 0: Picture1.Print 0
151 Picture1.CurrentX = 63: Picture1.CurrentY = 0: Picture1.Print "时间/S"
152 Picture1.CurrentX = 0.2: Picture1.CurrentY = 38: Picture1.Print "温度/℃"
153 
154 For i = 1 To 12
155    Picture1.Line (0, i * 3)-(60, i * 3), RGB(180, 180, 180)
156 Next i
157 
158   For i = 1 To 20
159     Picture1.Line (i * 3, 0)-(i * 3, 36), RGB(180, 180, 180)
160     Picture1.CurrentX = i * 3 - 1.2: Picture1.CurrentY = 0: Picture1.Print i * 3
161   Next i
162 
163 
164 For j = 1 To 12
165   Picture1.CurrentX = -2.7: Picture1.CurrentY = j * 3 + 1: Picture1.Print j * 3
166 Next j
167 
168 
169 
170 
171 
172 
173 
174 
175 End Sub
176 
177 Private Sub MSComm1_OnComm()  MSComm事件
178 
179 Select Case MSComm1.CommEvent
180     Case comEvReceive
181     inputsignal = MSComm1.Input
182     
183        Text1.Text = inputsignal
184        If flag = 0 Then
185           Open "D:\温度记录\text1.txt" For Output As #1
186           Print #1, Format(Now, "AMPM(hh:mm:ss)") & "    " & Text1.Text
187           Close #1
188           flag = 1
189        Else
190           Open "D:\温度记录\text1.txt" For Append As #1
191           Print #1, Format(Now, "AMPM(hh:mm:ss)") & "    " & Text1.Text
192           Close #1
193        End If
194        
195        
196         
197       
198     Case Else
199     End Select
200 End Sub
201 
202 
203 
204 
205 
206 
207 
208 
209 
210 
211 
212 
213 
214 Private Sub Timer1_Timer()
215 
216 
217 If Val(Text1.Text) > Val(Text6.Text) Or Val(Text1.Text) < Val(Text7.Text) Then
218 
219 playsnd 2187, 100
220 Shape2.FillColor = RGB(255, 0, 0)
221 Else
222 Shape2.FillColor = RGB(0, 255, 0)
223 
224 End If
225 End Sub
226 
227 Private Sub Timer2_Timer()
228 Text5.Text = Now   获取系统日期与时间
229 Label11.Caption = Now
230 End Sub
231 
232 Private Sub Timer3_Timer()
233 
234 If Text1.Text = "" Then
235 MsgBox ("端口暂时未接收到数据!")
236 
237 End If
238 
239 End Sub
240 
241 Private Sub Timer4_Timer()
242  t = Second(Time)
243  s1(t) = Val(Text1)
244 
245  
246 计算均值
247  sum1 = sum1 + s1(t)
248  
249 ‘‘‘‘‘‘‘‘‘‘‘‘‘‘‘
250 If t <> 0 Then
251     Text12.Text = (sum1 / (t + 1))
252     
253     Picture1.Line (t - 1, s1(t - 1))-(t, s1(t)), RGB(255, 0, 0)
254    
255 End If
256 
257 If t = 59 Then
258 Picture1.Cls
259 sum1 = 0: sum2 = 0: sum3 = 0
260 Picture1.Line (-2, 0)-(68, 0)
261 Picture1.Line (0, 38)-(0, -2)
262 Picture1.CurrentX = -2: Picture1.CurrentY = 0: Picture1.Print 0
263 Picture1.CurrentX = 63: Picture1.CurrentY = 0: Picture1.Print "时间/S"
264 Picture1.CurrentX = 0.2: Picture1.CurrentY = 38: Picture1.Print "温度/℃"
265 
266 For i = 1 To 12
267   Picture1.Line (0, i * 3)-(60, i * 3), RGB(180, 180, 180)
268   Next i
269 
270 For i = 1 To 20
271   Picture1.Line (i * 3, 0)-(i * 3, 36), RGB(180, 180, 180)
272   Picture1.CurrentX = i * 3 - 1.2: Picture1.CurrentY = 0: Picture1.Print i * 3
273 Next i
274 
275 For j = 1 To 12
276  Picture1.CurrentX = -2.7: Picture1.CurrentY = j * 3 + 1: Picture1.Print j * 3
277 Next j
278 
279 
280 End If
281 
282 
283 End Sub

 

单片机课程设计——温控系统

原文:https://www.cnblogs.com/industrial-fd-2019/p/11013408.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!