I/O的使用 数据方向寄存器和数据寄存器的配置
I/O输入输出的使用:
数据方向寄存器与数据寄存器
寄存器的概念:
PORTA、PORTB、PORTE和PORTK端口
DDRx决定对应引脚配置为输出口还是输入口,如果某位为“0”,则对应引脚设定为输入口;如果某位为“1”,则对应引脚设定为输出口。MCU复位后,DDRx值为0x00,引脚默认为输入口。 需要注意的是,PORTE端口是一个特例,它的最低两位只能为输入口,所以PORTE端口的数据方向寄存器最低两位是只读位,读取这两位始终返回“0”。
数据寄存器(Px)
数据寄存器Px中的8位对应每个端口中的相应引脚,如果某端口的引脚被定义为输出时,写入数据寄存器Px中的数值,则从对应引脚输出;如果某端口的引脚被定义为输入时,可以读取数据寄存器Px对应引脚的电平值。 需要注意PORTE端口是一个特例,它的最低两位只能为输入口,所以PORTE端口的数据寄存器最低两位是只读位。
简单演示程序一、
1 #include <hidef.h> /* common defines and macros */ 2 #include "derivative.h" /* derivative-specific definitions */ 3 4 //************主函数************* 5 void main(void) 6 { 7 DDRA=0x0F;//数据方向寄存器7-0 八位设置为 十六进制数0F 二进制为0000 1111 高四位引脚为输入 低四位引脚为输出 8 PORTA=0x0A;//数据寄存器7-0 八位设置为 十六进制数0A 二进制为0000 1010 高四位引脚悬空 低四位引脚1号和三号输出高电平0号和2号输出低电平 9 }
此时,A端口0号和2号引脚所控制的 LED灯点亮,其余灯灭。
原因:1号和3号引脚因输出高电平而不亮。7号-4号因数据方向寄存器设置为输入状态,因此无法改变LED灯电路控制端(电路开断)
疑问:为什么输出低电平LED灯会亮,高电平不亮?
解答:
在单片机开发的过程中,LED灯的亮灭控制与传统电路开关有所不同。统灯的亮灭控制由电路火线220V的开断所控制,而单片机开发中,LED灯的亮灭大多数需结合单片机实际电路设计来对LED灯的控制端进行控制。
如图:
单片机控制引脚在二极管反向,此二极管功能为开关二极管。二极管在正向电压作用下电阻很小,处于导通状态,相当于一只接通的开关;在反向电压作用下,电阻很大,处于截止状态,如同一只断开的开关。因此当单片机控制引脚为输出低电平时,二极管正向电压>反向电压 电路导通,LED灯亮。
复杂例程:
//*******************************************// //*** 演示程序一 ***// // ******************************************// //*******************************************// //*描述: *// //* 此程序包含以下几个模块: *// //* 交通灯、矩阵键盘、继电器、拨码开关 *// //* *// //* 目的: *// //* 完成简单的I/O控制,熟悉基本C语言编程 *// //*******************************************// //用拨码开关来控制模块的调用// #include <hidef.h> /* common defines and macros */ #include "derivative.h" /* derivative-specific definitions */ //// //全局变量的定义 unsigned int waittime=0;//定义继电器延时计数变量 unsigned int jidianqi_star=0;//定义继电器开关 unsigned int juzhengjianpan_star=0; //矩阵键盘开关 unsigned int paomadeng_star=0; //跑马灯开关 unsigned int times=0;//跑马灯依次按键计数变量 //*************延时********************// void delay(unsigned int num) //接收无符号延时变量 num { int i; //定义延时变量 i //2重循环 for(num;num>0;num--) //num循环减1 { for(i=100;i>=0;i--); //在num循环减1内依次i循环减1 } } //****************继电器模块***********// void jidianqi(void) //无接收值继电器 { delay(2000);//定义 num=2000并调用延时函数 waittime++; // 继电器延时计数变量waittime+1 if(waittime<=1) // 继电器延时计数变量waittime<=1 { DDRK=0X30;//打开继电器两路输出电源 0X30 十六进制转二进制为 0011 0000 ,k端口数据方向寄存器4和5号引脚为输出 PORTK=0X20; // 0x20十六进制转二进制为 0010 0000 k端口数据寄存器第5号引脚高电平 红灯亮 } else //否则 即 继电器延时计数变量waittime>1 { DDRK=0X30; //打开继电器输出两路电源 0X30 十六进制转二进制为 0011 0000 k端口数据方向寄存器4和5号引脚为输出 PORTK=0X10; // 0x10十六进制转二进制为 0001 0000 k端口数据寄存器第4号引脚高电平 绿灯亮 } if(waittime==2) // 当继电器延时计数变量waittime=2时 { waittime=0;//重新 赋值 继电器延时计数变量为下次使用 } } //****************矩阵键盘模块*********// void juzhengjianpan(void)//无接收值的矩阵 { DDRH_DDRH0=1;//接通行扫描线电源 H端口数据方向寄存器0号引脚为输出 while(PTH_PTH4==0)//判断数据寄存器PH4引脚接受到按键按下的低电平信号 //默认输入 若加写DDRA=0;此按键屏蔽 PORTA_BIT7=0;//PA7引脚低电平通电 PORTA_BIT7=1;//PA7引脚高电平断电 while(PTH_PTH5==0)//判断数据寄存器PH5引脚接受到按键按下的低电平信号 //默认输入 若加写DDRA=0;此按键屏蔽 PORTA_BIT6=0;//PA6引脚低电平通电 PORTA_BIT6=1; //PA6 引脚高电平断电 while(PTH_PTH6==0)//判断数据寄存器PH6引脚接受到按键按下的低电平信号 //默认输入 若加写DDRA=0;此按键屏蔽 PORTA_BIT5=0; //PA5 引脚低电平通电 PORTA_BIT5=1; // PA5 引脚高电平断电 while(PTH_PTH7==0)//判断数据寄存器PH7引脚接受到按键按下的低电平信号 //默认输入 若加写DDRA=0;此按键屏蔽 PTM_PTM5=0;//PM5 引脚低电平通电 PTM_PTM5=1; // PM5 引脚高电平断电 DDRH_DDRH0=0; DDRH_DDRH1=1; while(PTH_PTH4==0) PORTA_BIT4=0; PORTA_BIT4=1; while(PTH_PTH5==0) PORTA_BIT3=0; PORTA_BIT3=1; while(PTH_PTH6==0) PORTA_BIT2=0; PORTA_BIT2=1; while(PTH_PTH7==0) PORTA_BIT1=0; PORTA_BIT1=1; DDRH_DDRH1=0; DDRH_DDRH2=1; while(PTH_PTH4==0) PTM_PTM7=0; PTM_PTM7=1; while(PTH_PTH5==0) PORTB_BIT2=0; PORTB_BIT2=1; while(PTH_PTH6==0) PORTB_BIT0=0; PORTB_BIT0=1; while(PTH_PTH7==0) PTM_PTM6=0; PTM_PTM6=1; DDRH_DDRH2=0; DDRH_DDRH3=1; while(PTH_PTH4==0) PORTK_BIT7=0; PORTK_BIT7=1; while(PTH_PTH5==0) PORTE_BIT2=0; PORTE_BIT2=1; while(PTH_PTH6==0) PORTE_BIT3=0; PORTE_BIT3=1; while(PTH_PTH7==0) PTM_PTM4=0; PTM_PTM4=1; DDRH_DDRH3=0; } //*****************拨码开关模块***********// void bomakaiguang(void) { DDRJ_DDRJ1=0; // 1 DDRJ_DDRJ0=0; // 2 DDRB_BIT1=0; // 3 DDRB_BIT3=0; // 4 /* DDRB_BIT4=0; // 5 //此处拨码暂时无用 DDRB_BIT5=0; // 6 DDRB_BIT6=0; // 7 DDRA_BIT0=0; // 8 */ if(PTJ_PTJ1==1) //1号开关接通 { jidianqi_star=1; } else { jidianqi_star=0; //定义继电器开关 } if(PTJ_PTJ0==1) //2号开关接通 { juzhengjianpan_star=1; } else { juzhengjianpan_star=0; //矩阵键盘开关打开 } if(PORTB_BIT1==1) //3号开关接通打开 { paomadeng_star=1; } else { paomadeng_star=0; //跑马灯开关打开 } } //*****************LED初始化*******************// void LED_init() { DDRA=0XFE;//转换为2进制1111 1110 打开7654321 DDRB=0X05; //转换为2进制 0101打开30 DDRE=0X0C; //转换为2进制 1100打开32 DDRK=0X80; //转换为2进制 1000 0000打开7 DDRM=0XF0; //转换为2进制 1111 0000打开7654 PORTA=0XFE; //转换为2进制 1111 1110 打开7654321 PORTB=0X05; //转换为2进制 0101打开30 PORTE=0X0C; //转换为2进制 1100打开32 PORTK=0X80; //转换为2进制 1000 0000打开7 PTM=0XF0; //转换为2进制 1111 0000打开7654 } //*****************LED模块*************// void paomadeng() { times++; //时间累加依次按键 switch(times)//一对多选择time作为输入 注意!!!!低电平灯亮 高电平灯灭 { case 1:PORTA_BIT7=0;PORTE_BIT3=1;break;//time=1时,按下case 1按键执行PA7低电平灯亮,PE3高电平灯灭 break执行完后跳出 case 2:PORTA_BIT6=0;PORTA_BIT7=1;break; // time=2时,按下case 2按键执行PA6低电平灯亮,PA7高电平灯灭 case 3:PORTA_BIT5=0;PORTA_BIT6=1;break; case 4:PORTA_BIT4=0;PORTA_BIT5=1;break; case 5:PORTA_BIT3=0;PORTA_BIT4=1;break; case 6:PORTA_BIT2=0;PORTA_BIT3=1;break; case 7:PTIM=0X7F;PORTA_BIT2=1; break; // 0x7f转换2进制为0111 1111 M端口6543210号高电平,PA2高电平灯灭 case 8:PORTB_BIT2=0;PTM=0XFF; break; // PB2低电平灯亮,0xff转换2进制为1111 1111 M端口76543210号高电平灯灭 case 9:PORTB_BIT0=0;PORTB_BIT2=1;break; case 10:PORTK_BIT7=0;PORTB_BIT0=1;break; case 11:PORTE_BIT2=0;PORTK_BIT7=1; break; case 12:PORTE_BIT3=0;PORTE_BIT2=1; break; case 13:PTM=0XD0;PORTE_BIT3=1; break; // 0xd0 转换2进制为 0110 1000 M端口653号高电平其余为低,PE3高电平灯灭 case 14:PORTA_BIT1=0;PTM=0XFF; break;//PA1低电平灯亮 PTM 0xff 转换2进制为 1111 1111 M端口76543210号高电平 case 15:PTM=0XB0;PORTA_BIT1=1; break;//PTM 0xb0 转换2进制为 1011 0000 M端口754高电平其余为低,PA1高电平 case 16:PTM=0XE0;PTM=0XFF; break; // 0xe0 转换2进制为 1110 0000 M端口765高电平其余为低,0xff 转换2进制为 1111 1111 M端口76543210高电平 case 17:PTM=0XFF; break; // 0xff 转换2进制为 1111 1111 M端口76543210高电平 default:break;//跳出按键 } delay(500);//调用延时函数传值 500 if(times==17)//如果 跑马灯依次按键计数变量time=17 times=0;//重新赋值为0 为下次使用 } //**************主函数*****************// void main(void) { LED_init(); //LED灯初始化 for(;;) { bomakaiguang(); //拨码开关 if(jidianqi_star==1) //如果继电器通电 { jidianqi(); //继电器 } if(juzhengjianpan_star==1) { juzhengjianpan(); //矩阵键盘 } if(paomadeng_star==1) { paomadeng(); //跑马灯 } } }