荟聚奇文、博采众长、见贤思齐
当前位置:公文素材库 > 报告体会 > 工作报告 > 单片机实训报告

单片机实训报告

网站:公文素材库 | 时间:2019-05-29 22:35:35 | 移动端:单片机实训报告

单片机实训报告

一.实训目的:

单片机专周实训是在学习完单片机应用技术课程之后开设的两周实训课程,在课程学习中,通过理论与实验相结合的学习,同学们已经掌握了单片机基本的使用方法,但是教材上的例子比较简单,扩展的空间不大,因此此次实训的目的是为了加强同学们对单片机开发流程的认识,加深对单片机I/O口扩展与外围器件的使用,加强同学们的职业素养,加强同学们的实际动手能力与调试能力,从而实现从理论到实践的升华。

二.实验设备:

1.单片机实验板2.计算机

3.ISIS7Professional、SuperPro等相关调试编程软件4.5V电源5.烧录器

三.实训要求:

本次实训的项目是使用单片机制作一个数字温度计,2位7段数码管用以显示两位温度数据。实训过程先使用仿真软件实现电路的仿真,再使用万用板焊接电路,实现功能。要求仿真通过,实训态度认真,制作电路整洁,能实现功能。

设计要求:使用热敏电阻作为温度传感器,单片机作为处理芯片,根据佛山

的气候,要求温度显示数据范围为从0℃~45℃,分辨率为1℃,数码管显示采用动态扫描显示方式。

四.实训电路:

五.设计过程:

根据开发的要求,热敏电阻作为温度传感器,必须使用直流偏置电路和AD转换器,单片机接收AD转换器的数据,对照预先做好的温度数据查表,查到了相应的温度数据,送到数码管动态显示。硬件结构图如下图。

因此该系统重点解决的问题是热敏电阻的使用与AD转换器的使用,而多位7段数码管的动态显示已经非常熟悉了,因此不做过多的阐述。下面对一些重点问题进一步进行分析。

热敏电阻偏置电路电压

AD转换器数据51单片机数码管控制1.热敏电阻:

热敏电阻器有NTC与PTC两种,NTC是NegativeTemperatureCoefficient的缩写,意思是负的温度系数,泛指负温度系数很大的半导体材料或元件,所谓NTC热敏电阻器就是负温度系数热敏电阻器。它是以锰、钴、镍和铜等金属氧化物为主要材料,采用陶瓷工艺制造而成的。这些金属氧化物材料都具有半导体性质,因为在导电方式上完全类似锗、硅等半导体材料。温度低时,这些氧化物材料的载流子(电子和孔穴)数目少,所以其电阻值较高;随着温度的升高,载流子数目增加,所以电阻值降低。NTC热敏电阻器在室温下的变化范围为100~1M,温度系数为2%~6.5%。NTC热敏电阻器可广泛应用于温度测量、温度补偿、抑制浪涌电流等场合。

NTC热敏电阻专业术语:(1)零功率电阻值RT()

RT指在规定温度T时,采用引起电阻值变化相对于总的测量误差来说可以忽略不计的测量功率测得的电阻值。

电阻值和温度变化的关系式为

RT=RNexpB(1/T1/TN)

RT:在温度T(K)时的NTC热敏电阻阻值。RN:在额定温度TN(K)时的NTC热敏电阻阻值。T:规定温度(K)。

B:NTC热敏电阻的材料常数,又叫热敏指数。exp:以自然数e为底的指数(e=2.71828…)。

该关系式是经验公式,只在额定温度TN或额定电阻阻值RN的有限范围内才具有一定的精确度,因为材料常数B本身也是温度T的函数。

(2)额定零功率电阻值R25()

根据国家标准规定,额定零功率电阻值是NTC热敏电阻在基准温度25℃时测得的电阻值R25,这个电阻值就是NTC热敏电阻的标称电阻值。通常所说的NTC热敏电阻多少阻值,亦指该值。

(3)材料常数(热敏指数)B值(K)B值被定义为

BT1T2RlnT1T2T1RT2

RT1:温度T1(K)时的零功率电阻值。RT2:温度T2(K)时的零功率电阻值。T1,T2:两个被指定的温度(K)。

对于常用的NTC热敏电阻,B值的范围一般为201*K~6000K。

本次实训所使用NTC(负温度系数)热敏电阻型号为MF58-503-390,其标称阻值R25为50KΩ,材料常数B值为3900K(见型号的最后的三位数,补0)。

根据上述公式,我们可以推算出MF58-503-390在0~99℃的电阻值,可以使

用excel表格公式推算,十分方便,当然也可以参见课本的数据表格。

(4)热敏电阻偏置电路

VCC171415818192021D0D1D2D3D4D5D6D7ABCVR(+)12热敏电阻本身是无源元件,只是温度变化导致电阻值变化,因此使R720K16用时必须外接偏置电路,从而实现温度变化导致电压(电流)的变化。VR(-)最理想的情况是使用电流源串联热敏电阻,电流恒定,电阻变化直接导25IC2ADC0809致热敏电阻两端电压与热敏电阻呈线性变化,但是电流源电流相对复杂,262423使用的元器件太多,因此在温度计这样精度不高的场合并不适合。

109226OEALESC7简单的偏置电路可以使用右图的电路,电路简单,而且线性化较好,EOCCLK比较适合于简单的测温电路。因此我们采用这种偏置电路。IN0IN1IN2IN3IN4IN5IN6IN7272812345RTR8100K

2.AD转换器:

本次实训使用ADC0809芯片,在设计电路的时候一定要预先规划好0809的使用方式,具体使用查询方法、中断方法还是定时访问方法可以自己选择,因此电路的灵活性很强,编程也随着硬件变化而变化。

3.数码管显示

数码管显示使用动态扫描方式,为了减少干扰和提高单片机的稳定性,驱动数码管使用一个74LS04(非门)驱动。

六.实训程序:

ORG0000HLOOP:CLRP2.2SETBP2.2JNBP2.1,$CLRP2.0MOVA,P0SETBP2.0CLRC

SUBBA,#2CH

MOVDPTR,#TEMPTABMOVCA,@A+DPTRSETBP3.1SETBP3.MOVB,#10DIVABMOVR3,AMOVR4,B

MOVDPTR,#DIGITTABMOVA,R3

MOVCA,@A+DPTRMOVP1,ACLRP3.2

ACALLDELAYMOVA,R4

MOVCA,@A+DPTRSETRP3.2MOVP1,ACLRP3.1

ACALLDELAYAJMPLOOPDELAY:MOVR6,#2

D1:MOVR7.#250D2:NOP

DJNZR7,D2DJNZR6,D1RET

DIGITTAB:

DB0C0HDB0F9HDB0A4HDB0B0HDB099HDB092HDB082HDB0F8HDB080HDB090HDB08EH

TEMPTAB:

DB90,89,88,97,100,86,85,84,83,100,82,81,100,80DB79,100,78,77,100,76,75,100,74,100,73,100,72,71DB100,70,100,69,100,68,100,67,100,66,100,65,100,64DB100,63,100,62,100,61,100,60,100,100,59,100,58,100DB57,100,100,56,100,55,100,54,100,100,53,100,52,100DB100,51,100,50,100,100,49,100,48,100,100,47,100,46DB100,100,45,100,100,44,100,43,100,100,42,100,100,41DB100,40,100,100,39,100,38,100,100,37,100,100,36,1DB35,100,100,34,100,100,33,100,32,100,100,31,100,30DB100,100,29,100,28,100,100,27,100,26,100,100,25,100DB24,100,100,23,100,22,100,21,100,20,100,100,19,100DB18,100,17,100,16,100,15,100,14,100,13,100,12,100DB11,100,10,9,100,8,100,7,6,100,5,4,100,3DB2,1,100,0END

七.实训心得:

通过几天的实训和刘志远老师精心备课的教导,我在理论的基础上更深刻的掌握了单

片机的深层内容及实际生活中的应用,实训锻炼了自己动手能力和思维能力。经过这几个星期的实训,我懂了单片机温度显示器的工作原理:天气的高低靠热敏电阻来反应出分压后出来相对应的电压用ADC0809数模转换的芯片把相对应的电压反馈到单片机里,单片机内部程序已经编译好温度的精度(即是分辨率)然后用动态七段数码管显示出相对应的温度来,最后焊接出实物,用手紧贴住热敏电阻温度随手贴的时间不断上升放手后温度恢复成室温的温度,调试成功。

实训让我对单片机控制系统的研究产生浓厚的兴趣,还让我了解了怎样制作单片机烧录器及程序的烧录,在此以后,我会更多的去了解这个奇妙的领域。

扩展阅读:单片机实训报告心得

广东轻工职业技术学院

实训报告

实训项目系别:专业:班级:姓名:学号:指导老师:实训地点:实训时间:

单片机实训电子通信工程系应用电子技术嵌入式091班11222

201*080202316丁向荣、赵慧第三实训楼C309201*年1月10日至1月1

前言

单片机应用技术是现代电子设计的核心技术,学习单片机只是就是要将单片机应用到电子产品中,以单片机为控制核心实现电子系统所需实现的功能。单片机的应用能力很多程度上决定了电子类专业学生电子设计与电子应用的水平与能力,尤其是高职学生更是如此。

本项目要求设计一个简单的电子时钟,用六位LED数码管实现电子时钟的功能,显示方式为时、分、秒,采用24h(小时)计时方式,使用按键开关可实现时分调整。

通过电子闹钟项目的课题设计,让同学

们体验项目设计的要点,了解项目设计的流程,加深对单片机应用知识的学习,体会团队协作的力量所在。为日后的嵌入式专业学习巩固基础。

目录

1.概述…………………………………………………………

1.1系统的作用

1.2系统的功能要求

2.系统硬件设计………………………………………………..

2.1系统的电路原理2.2电路原理图2.3各控制按钮控制功能说明.

3.系统软件设计……………………………………………….4.系统调试…………………………………………………….5.总结…………………………………………………………

1.概述

1.1系统的作用

本系统是利用AT89C51单片机结合6个七段显示器以24时制“时时分分秒秒”格式显示时间的电子定时闹铃,系统可以设置8组定时闹铃和1组倒计时功能;当定时闹铃和倒计结束时,该电子时钟通过蜂鸣器发出嘀嘀嘀响声;本系统还具有半点和整点报时功能,当现在时间为半点时会发出嘀的一声响,当现在时间为整点时报整点数响声。由于该电子定时闹铃有强大功能可以在多种场合下使用,利用七段显示器发光也可以在夜晚和黑暗场合下使用。1.2系统的功能要求

(1)使用6位七段显示器显示24时制时间。(2)时间显示格式为“时时分分秒秒”。(3)定时闹铃功能。(4)倒计时功能。

(5)半点报时功能:当现在时间为半点时,蜂鸣器发出“嘀”

一声响。

(6)整点报时功能:当现在时间为整点时,蜂鸣器发出现在时间整点数响声。

(7)当任一闹铃时间到时发出连续“嘀嘀嘀”响声,七段显示器显示“XHHMM”。

(8)当倒计时时间到时发出嘀嘀嘀响声,七段显示器显示“000000”。

(9)定时闹铃、倒计时和现在时间模式可以互相切换而不影响各自功能。

(10)具有4个按键来进行功能设置,可以设置当前时间、8组闹铃的时间设置和开关及倒计时的时间设置。

(11)通过复位按键可以重启系统。

2.系统的硬件设计

2.1系统的电路原理

(1)系统以AT89C51单片机为本电路的核心元件,通过单片机的P0.0~P0.7引脚和A102J排阻加上拉电压来驱动七段显示器段显示数字。

(2)通过单片机的P2.2~P2.7引脚连接A103J排阻拉升电压信号,控制6个8050NPN三极管使共阴极七段显示器连通接地来循

环点亮6位七段显示器。

(3)在七段显示器供电的同时由P0脚驱动显示不同数字。根据人眼的视觉暂留特点,调整延迟时间使所观察到时间数字是稳定的数字。

(4)系统使用了HYDZ蜂鸣器,通过单片机P3.7引脚连接8550PNP三极管推动发声。

(5)电路通过4个按键连接单片机P1.0~P1.3引脚低电平控制系统功能设置。

(6)单片机的复位电路,采用传统上电复位,通过Reset按键控制。

(7)电路可以通过+5V和+12V直流电供电,当使用+12V直流供电时,电路通过1个7805三端稳电器、2个35v100μF电解电容和1个50v10μF电解电容转换成+5V直流电供电。

(8)系统通过一个发光二极管指示电路供电是或正常。

2.2电路原理图

图示为数码管显示电路

图示为主程序电路图2.3各控制按钮控制功能说明

KEY0(按键INT0):调时向左移一位数接P3.0KEY1(按键INT1):当前位加1接P3.1KEY2(按键T0):当前位减1接P3.2KEY3(按键T1):确定调时时间接P3.3

S1:切换闹钟调时模式(高电平)接P3.4S2:中断程序(高电平),中断当前的闹钟或整点报时的响应接P3.5S3:暂停和开始计时(高电平)接P3.6

BELL:蜂鸣器接P3.7

当整点报时和闹钟响应的时候会响。

LED灯当整点报时和闹钟响应的时候会亮。

P1.0~P1.3分别接LED灯的高四位,P1.4~P1.7分别接灯的低四位。

P0.0~P0.7分别口接数码管的段选的a~h位

P2.0~P2.5口分别接数码管的位选的6~1位

3.软件设计

表一程序内存资源分配表

内存地址20H21H22H23H24H25H26H27H.027H.127H.227H.327H.427H.527H.6

变量名称作用说明SECONMINHOUR存放50毫秒计时存放0.5秒计时存放1秒计时存放1分计时存放1小时计时用于中断1(#6H)用于显示中的闪烁闹钟标志位允许响铃用于标志分、秒(1为秒),闹钟功能时也一样闹钟总开关(1为开)用于闪烁标志用于闪烁秒表标志表一程序内存资源分配表

内存地址27H.728H-29H30H-35H36H37H-39H40H变量名称作用说明DISPSP两组闹钟的标志位,默认值为0用于保存闪烁时的调时区地址存放调时区地址用于存放要显示的首字(例如秒)第一组闹钟的时分栈底秒表第二组闹钟的时分存放闹钟调分地址存放闹钟调时地址闹钟组的切换标志(默认值为0)切换(默认值为0)闹钟第二组开关(默认值为0)50H-52H53H-55H56H57H2AH.02AH.12AH.2

表二芯片端口资源分配表

芯片端口P1.0P1.1P1.2P1.3P1.7P0P2.2P2.3变量名称作用说明K1K2K3K4SPK操作键K1操作键K2操作键K3操作键K4压电喇叭控制信号七段显示器数数字形状控制控制时间小时的十位七段显示器亮灭控制时间小时的个位七段显示器亮灭表二芯片端口资源分配表

芯片端口P2.4P2.5P2.6P2.7P3.0P3.1P3.2P3.3

变量名称作用说明BELL控制时间分钟的十位七段显示器亮灭控制时间分钟的个位七段显示器亮灭控制时间秒钟的十位七段显示器亮灭控制时间秒钟的个位七段显示器亮灭蜂鸣器LED半秒闪烁LED显示第一组闹钟是否开启LED显示第二组闹钟是否开启表三寄存器资源分配表

组寄存器R0R1第0组R2R3R4R6、R7第1组

作用说明存放秒显示地址显示首址#06H#0FEH#3H延时初始值用于keyB、C用于中断R0R5

流程图显示如下:

开始系统初始化电子钟时分秒显示中断允许T0中断显示子程序按键子程序主程序流程图

12

调时0.3s闪烁显示中断

开始系统初始化判断中断S1=1?S2=1?S3=0?进入闹钟调时强制退出中断暂停计时返回计时结束功能选择中断

开始N开启按钮中断?Y继续计时进入按钮判断显示+1YKey3=0?Y退出按钮中断Key3=0?Key1=0?N调时位左移一位Key2=0?显示-1调时程序流程图

开始保护现场N中断6次?Y当前调整位熄灭恢复现场返回调时0.3s闪烁显示中断

源程序清单:

#include

#defineucharunsignedchar#defineled_dataP0//P0显示数码管当前位的数字#defineled_bitP2//P2控制当前数码管显示的位数

intb;

ucharconls=0x00;//记录秒分时的个位数ucharcons=0x00;//记录秒分时的十位数ucharcon=0x00;//记录调时程序当前位数ucharx=0x00;//记录闹钟

sbitkey0=P3^0;//key0控制调时位左移以一位sbitkey1=P3^1;//key1控制挑时当前位数字+1sbitkey2=P3^2;//key1控制挑时当前位数字-1sbitkey3=P3^3;//确定当前挑时中断程序sbitstop=P3^4;//用来暂时计时和启动计时sbitbaojing=P3^5;//用以响应整点报时和闹钟sbitnaozhong=P3^6;//用来开启闹钟调时程序sbitbeep=P3^7;//用来终止当前整点报时或闹钟响应

ucharcodetable[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x00};//数码管当前位0~9的显示码

uchardatascan_con[6]={0xFE,0xFD,0xFB,0xF7,0xEF,0xDF};//数码管左到右6个位的显示

uchardatadis[8]={0x00,0x00,0x00,0x00,0x00,0x00,0x0a,0x00};//数码管的显示码

uchardatatimedata[6]={0x00,0x00,0x00,0x00,0x00,0x00};//电子钟的初始时间:00:00:00

uchardatasecclock[6]={0x00,0x00,0x00,0x00,0x00,0x00};//闹钟调时的初始时间:00:00:00uchari;

display();//显示数码管函数申明keyscan();//调时按钮函数声明//alarmcolk();

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

/*1ms延时显示程序

*/

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

voiddelay(intz){intx,y;

for(x=0;x

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

/*初始化子程序*/

/************************************************************************/initializa(){

for(i=0;i{baojing=0;P1=0x00;delay(500);baojing=1;P1=0xff;delay(500);}}}

if(key3==0){con=0;x=0;TR1=0;ET1=0;TR0=1;ET0=1;}//关闭调时按钮中断,继续显示电子钟的时间elseif(naozhong==0)//开启调时按钮中断{EA=0;if(key0==0){delay(10);while(key0==0);if(dis[con]==10){dis[7]=dis[con];dis[con]=dis[6];dis[6]=dis[7];}con++;TR0=0;ET0=0;TR1=1;ET1=1;if(con>=6)//若左移位数超过6,则关闭调时按钮中断,继续显示电子钟的时间{con=0;TR1=0;ET1=0;TR0=1;ET0=1;}}if(con!=0){if(key1==0){delay(10);while(key1==0);timedata[con]++;//当前位数据+1switch(con){case1:case3:if(timedata[con]>=6)//1、3位满6进一{timedata[con]=0;

}break;case2:case4:if(timedata[con]>=10)进一{timedata[con]=0;}break;case5:if(timedata[con]>=3){timedata[con]=0;}break;default:;}dis[con]=timedata[con];dis[6]=0x0a;}}if(con!=0){if(key2==0){delay(10);while(key2==0);switch(con){case1:case3:if(timedata[con]==0){timedata[con]=0x05;的减1处理}else{timedata[con]--;}break;case2:case4:if(timedata[con]==0)

20

//2、4位满10

//5位满2清零

//1、3位为0时

//当前位数据-{timedata[con]=0x09;的减1处理}else{timedata[con]--;}break;case5:if(timedata[con]==0){timedata[con]=0x02;减1处理}else{timedata[con]--;}break;default:;}dis[con]=timedata[con];dis[6]=0x0a;}}EA=1;}elseif(naozhong!=0)断,功能类似上面{EA=0;if(key0==0){delay(10);while(key0==0);if(dis[x]>=10){dis[7]=dis[x];dis[x]=dis[6];dis[6]=dis[7];}x++;TR0=0;ET0=0;TR1=1;ET1=1;if(x>=6){x=0;TR1=0;ET1=0;TR0=1;ET0=1;}

21

//2、4位为0时

//当前位数据-1

//5位为0时的

//减1处理

//送显示数据

//开启调时按钮中

}

if(x=6){secclock[x]=0;}break;case2:case4:if(secclock[x]>=10){secclock[x]=0;}break;case5:if(secclock[x]>=3){secclock[x]=0;}break;default:;

}dis[x]=secclock[x];dis[6]=0x0a;}}if(x>=0){if(key2==0){delay(10);while(key2==0);switch(x){

case1:case3:if(secclock[x]==0){secclock[x]=0x05;}else{secclock[x]--;}break;case2:case4:if(secclock[x]==0){secclock[x]=0x09;}else{secclock[x]--;}break;case5:if(secclock[x]==0){secclock[x]=0x02;}else{secclock[x]--;}break;default:;}dis[x]=secclock[x];dis[6]=0x0a;}}EA=1;}

}

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

****/

/*0.3s闪烁中断小程序*/

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

voidtime_intt1(void)interrupt3{

EA=0;TR1=0;TH1=0X3C;TL0=0XB0;TR1=1;cons++;

if(cons==6)//50msx6=300ms=0.3s{cons=0x00;dis[7]=dis[con];dis[con]=dis[6];dis[6]=dis[7];}

EA=1;}

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

/*电子钟显示进位处理程序*/

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

voidtime_intt0(void)interrupt1{{inti,j,x=0;j=0;

if(naozhong==0&&stop==1){ET0=0;TR0=0;TH0=0X3C;TL0=0XB0;TR0=1;conls++;if(conls==20)//20次延时,秒+1{conls=0x00;timedata[0]++;if(timedata[0]>=10)//10s时,秒十位数+1{timedata[0]=0;timedata[1]++;if(timedata[1]>=6)//60s时,分+1{//5timedata[1]=0;timedata[2]++;

if(timedata[2]>=10)//10min时,分十位数+1{timedata[2]=0;timedata[3]++;if(timedata[3]>=6)//60min时,时+1{timedata[3]=0;timedata[4]++;if(beep==0){

for(i=1;i=10)时,时十位数+1{timedata[4]=0;timedata[5]++;if(timedata[5]==2)//当h等于24时,清零{if(timedata[4]==4){timedata[4]=0;timedata[5]=0;}}}}}}}for(b=0;b显示码{dis[b]=timedata[b];}}ET0=1;}

/*显示清零并转换成秒计时(原时间仍然保存)*//*elseif(jishi==1){for(j=0;j=10){timedata[0]=0;timedata[1]++;if(secclock[0]>=10){secclock[0]=0;secclock[1]++;}}if(timedata[1]>=6){timedata[1]=0;timedata[2]++;if(secclock[1]>=6){secclock[1]=0;secclock[2]++;}}if(timedata[2]>=10)

26

}}

{timedata[2]=0;if(secclock[2]>=10){secclock[2]=0;secclock[3]++;}}}}for(b=0;b

5.总结

AT89C51单片机作为嵌入式专业的入门基础,受到行业内的高度重视。作为一名高职高专的学生,最重要的是实际操作能力,而对于修读嵌入式专业的高职学生更是如此。单片机实训,敲开了同学们对知识求知若渴的大门。

本周的单片机实训项目课题是定时闹铃。刚接到课题时感觉毫无压力,觉得自己的能力应该很快就可以完成,因为本项目要实现的功能只不过是同等于价值2元的电子闹钟!

但是现实却击垮了浮夸的我们。程序设计无从入手,调试错误,单片机无响应……老师在讲解课题任务的时候确实是很简单,清晰明了。但是真正到我们设计的时候,错误接一连二。由于对汇编语言掌握不足,最终放弃汇编语言改换C语言编写程序。函数调用,设计循环语句,调用数组函数……

一步步慢慢深入,一点点渐渐掌握。最终,经过小组成员不停地编码,测试,运行,一个小项目终于完成。

项目虽然完成,但通过本次实训确实感触不少。于嵌入式行业而言,单片机谈得上是基础,但是就连这样一门基础我们也没有熟悉掌握,对于日后ARM的学习就更是困难。不过在实训中我们也学会了很多。项目设计、功能选定、搭建硬件工作环境、编写软件程序,程序下载测试、程序最终实现,以及在项目设计中的团队分工与合作。

嵌入式行业在我国日趋发展成熟,而嵌入式行业的人才

却是十分紧缺,这就取决于嵌入式行业对技术型人才要求高的特点。要想在嵌入式行业站稳脚,就必须要痛下苦工,敢于钻研。相信通过日后的专业知识学习,我们会在嵌入式学习的道路上越走越远。

友情提示:本文中关于《单片机实训报告》给出的范例仅供您参考拓展思维使用,单片机实训报告:该篇文章建议您自主创作。

来源:网络整理 免责声明:本文仅限学习分享,如产生版权问题,请联系我们及时删除。


单片机实训报告》由互联网用户整理提供,转载分享请保留原作者信息,谢谢!
链接地址:http://www.bsmz.net/gongwen/747935.html
相关文章