CT107D编程手册复习过程.docx
- 文档编号:26610700
- 上传时间:2023-06-20
- 格式:DOCX
- 页数:29
- 大小:25.56KB
CT107D编程手册复习过程.docx
《CT107D编程手册复习过程.docx》由会员分享,可在线阅读,更多相关《CT107D编程手册复习过程.docx(29页珍藏版)》请在冰豆网上搜索。
CT107D编程手册复习过程
一、IO口编程
IO编程,该开发板使用了573锁存器,通过P2口的5,6,7位连接3-8译码器,扩展出了8个口,其中4个口分别连接4个573锁存器,这里以LED的锁存器来举例:
原理图573:
分析代码:
P2=((P2&0x1f)|0x80);
其中0x1f=0001 1111,P2与0x1f进行与运算,高三位清零,其余位保持原来状态,不改变,即把控制3-8译码器的高三位留出来:
接着再或上0x80;容易发现0x80=1000 0000;或运算,与1或结果为1,与0或结果不变,所以或上0x80只需看P2的高三位,则高三位为100,对应3-8译码器的话,P2^7=1;P2^6=0;P2^5=0;
所以输出Y4=0;Y4再经过与非运算,看下图示:
则输出Y4C=1;即LED对应的锁存器的片选信号被选中,锁存器打通,接下来就可以对P0口进行操作,操作完之后,
P2=P2&0x1f;P2高三位直接清零,此时Y4C=0,则把锁存器锁上了。
类似的方法,数码管、蜂鸣器等都是如此操作,
选中锁存器代码:
P2=((P2&0x1f)|(这里填对应锁存器的位移号))。
二、 数码管动态扫描和定时器
数码管显示分为段选和位选,
数码管定义和显示函数:
Codeunsignedchartab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
unsignedchardspbuf[]={10,10,10,10,10,10,10,10};
unsignedchardspcom=0;
voiddisplay()
{
//段选,消隐
P2=((P2&0x1f)|0xe0);
P0=0xff;
P2=P2&0x1f;
//位选
P2=((P2&0x1f)|0xc0);
P0=(1< P2=P2&0x1f; //段码输入 P2=((P2&0x1f)|0xe0); P0=tab[dspbuf[dspcom]]; P2=P2&0x1f; if(++dspcom==8) dspcom=0; } 注意: 这里1左移dspcom位,刚开始dspcom=0,则1左移dspcom位依旧为1,接着dspcom每次自增1,1对应二进制00000001,即把1每次向左移,每次都比上一次多移一位,直至8位移完,对应8个数码管。 定时器配置: 这里只需记住定时器的配置,知道怎么使用就可以了。 首先有两个定时器,T0和T1,(也有的单片机有T2),定时器有4种工作方式0,1,2,3;其中最常用的是方式1(16位),其次是方式2(8位自动重装,串口通讯中断会用到)。 定时器需要配置: TMOD|=0x01;配置成使用定时器0,工作方式为1;同理使用定时器1工作方式1: TMOD|=0x10;则同时使用两个定时器且工作方式为1,那么可以: TMOD|=0x11; 定时器1配置成工作方式2: TMOD|=0x20; 接着配置(以定时器0举例): TH0=(65535-2000)/256;//配置初值 TL0=(65535-2000)%6; ET0=1; TR0=1;//定时0中断 EA=1;//总中断 定时器1也是同理的,只不过0要改成1. 接着定时中断函数和优先级: 定时器0 voidisr_timer_0(void)interrupt1 //默认中断优先级1 { TH0=(65536-2000)/256; TL0=(65536-2000)%6; //定时器重载 display(); } 定时器1: voidisr_timer_1(void) interrupt3//默认中断优先级3 { TH0=(65536-2000)/256; TL0=(65536-2000)%6; //定时器重载 display(); } 注意: 定时器0优先级为1,定时器1为3,串口中断优先级为4,总共有5个中断源,后面还会介绍外部中断和串口中断。 数码管动态扫描,显示函数放在定时中断函数里面,2ms扫一次是最稳定的! ! 三、 矩阵键盘 矩阵键盘需要死记了! 这里不再讲独立键盘。 第二种单片机键盘扫描代码(没有消抖): sfrP4^4=0xC0; //键盘定义 sbitr1=P3^0; //4行 sbitr2=P3^1; sbitr3=P3^2; sbitr4=P3^3; //4列 sbitc1=P4^4; sbitc2=P4^2; sbitc3=P3^5; sbitc4=P3^4; //读取矩阵键盘键值 unsignedcharkey_scan() { unsignedcharkey_value; r1=0; r2=r3=r4=1; c1=c2=c3=c4=1; if(! c1)key_value=0; elseif(! c2)key_value=1; elseif(! c3)key_value=2; elseif(! c4)key_value=3; r2=0; r1=r3=r4=1; c1=c2=c3=c4=1; if(! c1)key_value=4; elseif(! c2)key_value=5; elseif(! c3)key_value=6; elseif(! c4)key_value=7; r3=0; r2=r1=r4=1; c1=c2=c3=c4=1; if(! c1)key_value=8; elseif(! c2)key_value=9; elseif(! c3)key_value=10; elseif(! c4)key_value=11; r4=0; r2=r3=r1=1; c1=c2=c3=c4=1; if(! c1)key_value=12; elseif(! c2)key_value=13; elseif(! c3)key_value=14; elseif(! c4)key_value=15; returnkey_value; } 四、 串口通讯和串口中断 串口中断配置只需记住几个寄存器就行了, 初始化: SCON=0x50;//串口配置成模式1 TMOD|=0x20;//定时器1,方式2,8位自动重装 TH1=256-(unsigbedchar)(SYSTEMCLOK/BAUDRATE/384+0.5);//定时初值 ES=1; //串口中断打开 TR1=1; //启动定时器1 EA=1; //总中断打开 这里必须使用定时器1,不能用定时器0. 下面是模块化的函数: voidUart_Init() { SCON=0x50; TMOD|=0x20; TH1=256-(SYSREMCLOCK/BAUDRATE/384+0.5); ES=1; TR1=1; EA=1; } voidUartSend(unsignedchar*pBuff,intlength) { unsignedcharc; inti=0; for(i=0;i { c=pBuff; SBUF=c; while(TI==0); TI=0; } } 接收数据可以这样写: 定义全局变量: unsignedcharuart_buf[100];//串口缓冲区 unsignedint uart_Count=0;//串口数据长度 voiduart_inte()interrupt4 { unsignedcharc; if(RI) { RI=0; c=SBUF; uart_buf[uart_Count]=c; uart_Count++; } } 如果可以指定的接收,可以这样写 //串口中断服务函数 voidisr_uart(void)interrupt4{ if(RI){ RI=0; //清除接收标志位 rxbuf[rxcnt]=SBUF; if(rxbuf[rxcnt]=='\n'){ rxcnt=0; rx_over=1; ES=0; //回车为接收结束标志,检测到回车符后,关闭串口中断 } else{ rxcnt++; } } } 当接收完一帧数据时关闭串口中断,设一个标志位,处理完之后再打开。 #include"reg51.h" #include"intrins.h" typedefunsignedcharBYTE; typedefunsignedintWORD; BYTEcode_tab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff}; chararry[10]="ICANPLAY"; unsignedcharx; #defineFOSC11059200//12000000L //系统频率 #defineBAUD115200 //串口波特率 #defineNONE_PARITY 0 //无校验 #defineODD_PARITY 1 //奇校验 #defineEVEN_PARITY 2 //偶校验 #defineMARK_PARITY 3 //标记校验 #defineSPACE_PARITY 4 //空白校验 #definePARITYBITNONE_PARITY //定义校验位 sfrAUXR =0x8e; //辅助寄存器 sfrP_SW1 =0xA2; //外设功能切换寄存器1 #defineS1_S00x40 //P_SW1.6 #defineS1_S10x80 //P_SW1.7 sbitP22=P2^2; bitbusy; voidSendData(BYTEdat); voidSendString(char*s); voidmain() { ACC=P_SW1; ACC&=~(S1_S0|S1_S1); //S1_S0=0S1_S1=0 P_SW1=ACC; //(P3.0/RxD,P3.1/TxD) // ACC=P_SW1; // ACC&=~(S1_S0|S1_S1); //S1_S0=1S1_S1=0 // ACC|=S1_S0; //(P3.6/RxD_2,P3.7/TxD_2) //P_SW1=ACC; // // ACC=P_SW1; // ACC&=~(S1_S0|S1_S1); //S1_S0=0S1_S1=1 // ACC|=S1_S1; //(P1.6/RxD_3,P1.7/TxD_3) //P_SW1=ACC; //#if(PARITYBIT==NONE_PARITY) SCON=0x50; //8位可变波特率 //#elif(PARITYBIT==ODD_PARITY)||(PARITYBIT==EVEN_PARITY)||(PARITYBIT==MARK_PARITY) // SCON=0xda; //9位可变波特率,校验位初始为1 //#elif(PARITYBIT==SPACE_PARITY) // SCON=0xd2; //9位可变波特率,校验位初始为0 //#endif AUXR=0x40; //定时器1为1T模式 TMOD=0x20; //定时器1为模式2(8位自动重载) TL1=(256-(FOSC/32/BAUD)); //设置波特率重装值 TH1=(256-(FOSC/32/BAUD)); TR1=1; //定时器1开始工作 ES=1; //使能串口中断 EA=1; while (1) { // SendString(arry); SendString("ICANPLAY~~\r\n");//上位机显示接收文本模式 // SendData(x); } } voidUart()interrupt4using1 { if(RI)//单片机接收数据,发送数字0~9,可在数码管上显示,发送hex模式 { RI=0; //清除RI位 // P0=SBUF; x=SBUF;//将缓存器的数据赋值给x P0=0xff; //消隐 P2|=0xe0; P2&=0x1f; P0=code_tab[x]; //段选 P2|=0xe0; P2&=0x1f; P0=0x01; //位选第一位 P2|=0xc0; P2&=0x3f; } if(TI) { TI=0; //清除TI位 busy=0; //清忙标志 } } voidSendData(BYTEdat) { while(busy); //等待前面的数据发送完成 ACC=dat; //获取校验位P(PSW.0) if(P) //根据P来设置校验位 { #if(PARITYBIT==ODD_PARITY) TB8=0; //设置校验位为0 #elif(PARITYBIT==EVEN_PARITY) TB8=1; //设置校验位为1 #endif } else { #if(PARITYBIT==ODD_PARITY) TB8=1; //设置校验位为1 #elif(PARITYBIT==EVEN_PARITY) TB8=0; //设置校验位为0 #endif } busy=1; SBUF=ACC; //写数据到UART数据寄存器 } voidSendString(char*s) { while(*s) //检测字符串结束标志 { SendData(*s++); //发送当前字符 } } 记不住可以看手册! ! #include"reg51.h" #include"intrins.h" typedefunsignedcharBYTE; typedefunsignedint WORD; #defineFOSC11059200L #defineBAUD115200 sfrAUXR=0x8e; //辅助寄存器 sbitP22=P2^2; bitbusy; voidSendData(BYTEdat); voidSendString(char*s); voidmain() { SCON=0x50; AUXR=0x40;//设置定时器T1为1T,即一个机器周期模式 TMOD=0x20; TL1=(256-(FOSC/32/BAUD)); TH1=(256-(FOSC/32/BAUD)); TR1=1; ES=1; EA=1; SendString("Hello"); while (1); } voidUart()interrupt4using1 { if(RI) { RI=0; P0=SBUF; } if(TI) { TI=0; busy=0; } } voidSendData(BYTEdat) { while(busy); busy=1; SBUF=dat; } voidSendString(char*s) { while(*s) { SendData(*s++); } } 五、 外部中断的使用 #include sbitL1=P0^0; intmain(){ IT0=1;//IT0=1,下降沿触发外部中断0,IT0=0边沿触发 EX0=1;//使用外部中断0 EA=1; while (1){ } } voidEx_int0()interrupt0//外部中断优先级最高 { P2=((P2&0x1f)|0x80); L1=~L1; P2=(P2&0x1f); } 其中,外部中断的引脚控制是P3^2,P3^3,即对应独立按键的S5,S4。 六、 实时时钟DS1302的使用 蓝桥杯提供函数,解释为: 里面的命令和写入的数据可以看芯片手册: 左侧的READ、WRITE分别是读写的命令,BIT7-BIT0是要写入的数据,根据需要进行配置。 DS1302只需记住这两个函数即可: Write_Ds1302(,)与Read_Ds1302(x),配置看手册。 重点: 芯片表说明: 第一行: 秒->因为秒的范围是0-59,所以6,5,4位表示秒的十位,3,2,1,0表示个位,十位最大是5,所以三位即可。 第二行: 跟上面一样; 第三行: 7位: 1为12小时制,0为24小时制;5位: 12小时制时为0表示上午,1表示下午,24小时制时,和4位一起表示小时的十位; 其余的时间一样的表示。 倒数第二行: 只看7位: 为1时禁止写数据,所以开始写数据时必须置0; 读数时: ! ! 需要加“写操作这一行代码”。 读的话直接按照命令读即可。 DS1302进阶(BCD码转换): 解决之前60秒不能进位的问题。 1)写入初始值时,要把10十进制数转换为BCD码, 例: 写入时间->17: 58: 50 Ds1302_Single_Byte_Write(0x8e,0x00);//写操作 Ds1302_Single_Byte_Write(0x85,((17/10)<<4|(17)));//写时 Ds1302_Single_Byte_Write(0x83,((58/10)<<4|(58)));//写分 Ds1302_Single_Byte_Write(0x81,((50/10)<<4|(50)));//写秒 Ds1302_Single_Byte_Write(0x8e,0x80);//写保护 即转换的公式是: ((Value/10)<<4|(Value)),可以写一个settime()函数。 2)读数: 读回来的数要进行转换成十进制数 ((ReadValue&0x70)>>4)*10+(ReadValue&0x0F); 八进制转十进制-> ReadValue=Ds1302_Single_Byte_Read(0x85); hour=((ReadValue&0x70)>>4)*10+(ReadValue&0x0F); ! ! (这句一定不要省) Ds1302_Single_Byte_Write(0x00,0x00);//写操作 ReadValue=Ds1302_Single_Byte_Read(0x83); minute=((ReadValue&0x70)>>4)*10+(ReadValue&0x0F); Ds1302_Single_Byte_Write(0x00,0x00);//写操作 ReadValue=Ds1302_Single_Byte_Read(0x81); sec=((ReadValue&0x70)>>4)*10+(ReadValue&0x0F); Ds1302_Single_Byte_Write(0x00,0x00);//写操作 显示: dspbuf[0]=hour/10; dspbuf[1]=hour; dspbuf[2]=minute/10; dspbuf[3]=minute; dspbuf[4]=sec/10; dspbuf[5]=sec; 七、 PCF8591与IIC总线的使用 (1) IIC总线的使用: 比赛提供了IIC的两个库文件,IIC.h;IIC.c,其中需要注意的函数是: 其中,该函数是初始化的,当使用AD
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- CT107D 编程 手册 复习 过程