找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 5355|回复: 5
收起左侧

单片机8个独立式键盘驱动程序(编程模板)

[复制链接]
ID:350104 发表于 2018-11-6 16:26 | 显示全部楼层 |阅读模式
  1. #define KEY P1 //键盘所连接的I/O接口组定义

  2. /*********************************************************************************************
  3. 函数名:8个独立式键盘驱动程序
  4. 调  用:? = Key ();
  5. 参  数:无
  6. 返回值:unsigned char 键值0~8
  7. 结  果:有键按下时返回值为键值1~8,无键按下时返回值为0
  8. 备  注:在主函数中不断调用
  9. /**********************************************************************************************/
  10. unsigned char Key ( ){ //8个独立键盘处理程序
  11. unsigned char a,b;
  12. KEY = 0xff; //设定键盘初始电平状态
  13. if (KEY != 0xff){ //读取键盘状态是否改变
  14.    Delay (20); //延时20ms去抖动
  15.    if (KEY != 0xff){ //重新读取
  16.           a = KEY; //寄存状态值到a
  17. }
  18.         switch(a){ //键盘状态查表
  19.            case 0xfe: b = 1; break;
  20.            case 0xfd: b = 2; break;
  21.            case 0xfb: b = 3; break;
  22.            case 0xf7: b = 4; break;
  23.            case 0xef: b = 5; break;
  24.            case 0xdf: b = 6; break;
  25.            case 0xbf: b = 7; break;
  26.            case 0x7f: b = 8; break;
  27.            default:   b = 0 ; break;
  28.            }
  29.         }
  30. return (b); //将b中的键值代号送入函数返回值
  31. }
  32. /**********************************************************************************************/


  33. /*********************************************************************************************
  34. 程序名:    8位ADC转换实验程序

  35.                                                                
  36. /*********************************************************************************************
  37. 说明:
  38. PC串口端设置 [ 4800,8,无,1,无 ]
  39. 将ADC读出的数值通过串口以十六进制方式显示。

  40. /*********************************************************************************************/

  41. #include <STC12C2052AD.H> //单片机头文件
  42. #include <intrins.h>        //51基本运算(包括_nop_空函数)

  43. /*********************************************************************************************
  44. 函数名:毫秒级CPU延时函数
  45. 调  用:DELAY_MS (?);
  46. 参  数:1~65535(参数不可为0)
  47. 返回值:无
  48. 结  果:占用CPU方式延时与参数数值相同的毫秒时间
  49. 备  注:应用于1T单片机时i<600,应用于12T单片机时i<125
  50. /*********************************************************************************************/
  51. void DELAY_MS (unsigned int a){
  52.         unsigned int i;
  53.         while( a-- != 0){
  54.                 for(i = 0; i < 600; i++);
  55.         }
  56. }
  57. /*********************************************************************************************/

  58. /*********************************************************************************************
  59. 函数名:UART串口初始化函数
  60. 调  用:UART_init();
  61. 参  数:无
  62. 返回值:无
  63. 结  果:启动UART串口接收中断,允许串口接收,启动T/C1产生波特率(占用)
  64. 备  注:振荡晶体为12MHz,PC串口端设置 [ 4800,8,无,1,无 ]
  65. /**********************************************************************************************/
  66. void UART_init (void){
  67.         //EA = 1; //允许总中断(如不使用中断,可用//屏蔽)
  68.         //ES = 1; //允许UART串口的中断

  69.         TMOD = 0x20;        //定时器T/C1工作方式2
  70.         SCON = 0x50;        //串口工作方式1,允许串口接收(SCON = 0x40 时禁止串口接收)
  71.         TH1 = 0xF3;        //定时器初值高8位设置
  72.         TL1 = 0xF3;        //定时器初值低8位设置
  73.         PCON = 0x80;        //波特率倍频(屏蔽本句波特率为2400)
  74.         TR1 = 1;        //定时器启动   
  75. }
  76. /**********************************************************************************************/

  77. /*********************************************************************************************
  78. 函数名:UART串口发送函数
  79. 调  用:UART_T (?);
  80. 参  数:需要UART串口发送的数据(8位/1字节)
  81. 返回值:无
  82. 结  果:将参数中的数据发送给UART串口,确认发送完成后退出
  83. 备  注:
  84. /**********************************************************************************************/
  85. void UART_T (unsigned char UART_data){ //定义串口发送数据变量
  86.         SBUF = UART_data;        //将接收的数据发送回去
  87.         while(TI == 0);                //检查发送中断标志位
  88.         TI = 0;                        //令发送中断标志位为0(软件清零)
  89. }
  90. /**********************************************************************************************/
  91. /*********************************************************************************************
  92. 函数名:8位A/D转换初始化函数
  93. 调  用:Read (?);
  94. 参  数:输入的端口(0000 0XXX 其中XXX是设置输入端口号,可用十进制0~7表示,0表示P1.0,7表示P1.7)
  95. 返回值:无
  96. 结  果:开启ADC功能并设置ADC的输入端口
  97. 备  注:适用于STC12C2052AD系列单片机(必须使用STC12C2052AD.h头文件)
  98. /**********************************************************************************************/
  99. void Read_init (unsigned char CHA){
  100.         unsigned char AD_FIN=0; //存储A/D转换标志
  101.     CHA &= 0x07;            //选择ADC的8个接口中的一个(0000 0111 清0高5位)
  102.     ADC_CONTR = 0x40;                //ADC转换的速度(0XX0 0000 其中XX控制速度,请根据数据手册设置)
  103.     _nop_();
  104.     ADC_CONTR |= CHA;       //选择A/D当前通道
  105.     _nop_();
  106.     ADC_CONTR |= 0x80;      //启动A/D电源
  107.     DELAY_MS(1);            //使输入电压达到稳定(1ms即可)
  108. }
  109. /**********************************************************************************************/
  110. /*********************************************************************************************
  111. 函数名:8位A/D转换函数
  112. 调  用:? = Read ();
  113. 参  数:无
  114. 返回值:8位的ADC数据
  115. 结  果:读出指定ADC接口的A/D转换值,并返回数值
  116. 备  注:适用于STC12C2052AD系列单片机(必须使用STC12C2052AD.h头文件)
  117. /**********************************************************************************************/
  118. unsigned char Read (void){
  119.         unsigned char AD_FIN=0; //存储A/D转换标志
  120.     ADC_CONTR |= 0x08;      //启动A/D转换(0000 1000 令ADCS = 1)
  121.     _nop_();
  122.     _nop_();
  123.     _nop_();
  124.     _nop_();
  125.     while (AD_FIN ==0){     //等待A/D转换结束
  126.         AD_FIN = (ADC_CONTR & 0x10); //0001 0000测试A/D转换结束否
  127.     }
  128.     ADC_CONTR &= 0xE7;      //1111 0111 清ADC_FLAG位, 关闭A/D转换,
  129. return (ADC_DATA);          //返回A/D转换结果(8位)
  130. }
  131. /**********************************************************************************************/
  132. /*********************************************************************************************
  133. 函数名:主函数
  134. 调  用:无
  135. 参  数:无
  136. 返回值:无
  137. 结  果:程序开始处,无限循环
  138. 备  注:
  139. /**********************************************************************************************/
  140. void main (void){
  141.         unsigned char R;
  142.         UART_init();//串口初始程序
  143.         Read_init(0);//ADC初始化
  144.         P1M0 = 0x01; //P1.7~.0:0000 0001(高阻)//注意:更改ADC通道时须同时将对应的IO接口修改为高阻输入。
  145.         P1M1 = 0x00; //P1.7~.0:0000 0000(强推)
  146.         while(1){
  147.             R = Read ();
  148.             UART_T (R); //串口小秘书,将ADC读出值送入串口显示
  149.         }
  150. }/**********************************************************************************************/

  151. #define KEY P1 //键盘所连接的I/O接口组定义

  152. /*********************************************************************************************
  153. 函数名:16个阵列式键盘驱动程序
  154. 调  用:? = Key ();
  155. 参  数:无
  156. 返回值:unsigned char 键值0~16
  157. 结  果:有键按下时返回值为键值1~16,无键按下时返回值为0
  158. 备  注:在主函数中不断调用
  159. /**********************************************************************************************/
  160. unsigned char Key (void){ //4*4阵列键盘处理程序
  161. unsigned char a,b,c;
  162. KEY = 0x0f; //设定键盘初始电平状态
  163. if (KEY != 0x0f){ //读取键盘状态是否改变
  164.    Delay (20); //延时20ms去抖动
  165.    if (KEY != 0x0f){ //重新读取
  166.           a = KEY; //寄存状态值到a
  167.         }
  168.         KEY = 0xf0; //设定键盘反向电平状态
  169.         c = KEY; //读取反向电平状态值到c
  170.         a = a|c; //a与c相或
  171.         switch(a){ //键盘状态查表
  172.            case 0xee: b = 1; break;
  173.            case 0xed: b = 2; break;
  174.            case 0xeb: b = 3; break;
  175.            case 0xe7: b = 4; break;
  176.            case 0xde: b = 5; break;
  177.            case 0xdd: b = 6; break;
  178.            case 0xdb: b = 7; break;
  179.            case 0xd7: b = 8; break;
  180.            case 0xbe: b = 9; break;
  181.            case 0xbd: b = 10; break;
  182.            case 0xbb: b = 11; break;
  183.            case 0xb7: b = 12; break;
  184.            case 0x7e: b = 13; break;
  185.            case 0x7d: b = 14; break;
  186.            case 0x7b: b = 15; break;
  187.            case 0x77: b = 16; break;
  188.            default:   b = 0 ; break;
  189.            }
  190.         }
  191. return (b); //将b中的键值代号送入函数返回值
  192. }
  193. /**********************************************************************************************/

  194. /*********************************************************************************************
  195. 程序名:STC系列单片机内部EEPROM 测试程序
  196. P1口接8个LED到VCC。
  197. 适用硬件:
  198. STC12C5AxxAD系列单片机
  199. STC12C52xxAD系列单片机
  200. STC11xx系列单片机
  201. STC10xx系列单片机
  202. 使用说明:
  203. 1,程序先别P1口高4位和低4位分别点亮一次。
  204. 2,检查EEPROM中对应地址内的值是否与用户测试值相同。
  205. 3,如果相同则P1.7上的LED亮,然后在P1口显示EEPROM中的值。
  206. 4,如果不同则P1.3上的LED亮,然后全片擦除EEPROM并写入用户测试值到指定地址。
  207. 注意:
  208. # 在第一次下载时为写入(第4步),复位后才会测试。
  209. # 当供电电源低于一定值时将不能写入EEPROM,详见数据手册。


  210. /*********************************************************************************************/
  211. #include <reg51.H>
  212. #include <intrins.H>
  213. /*********************************************************************************************/
  214. typedef unsigned char  INT8U;
  215. typedef unsigned int   INT16U;
  216. /*********************************************************************************************/
  217. //用于STC12C2052系列单片机时选择//
  218. sfr IAP_DATA    = 0xE2; //STC12C2052系列单片机的EEPRON操作地址是0xe2(以下类推)
  219. sfr IAP_ADDRH   = 0xE3;
  220. sfr IAP_ADDRL   = 0xE4;
  221. sfr IAP_CMD     = 0xE5;
  222. sfr IAP_TRIG    = 0xE6;
  223. sfr IAP_CONTR   = 0xE7;
  224. #define WD1        0x46        //使用STC12C2052系列单片机时,先写入0x46,然写入0xb9
  225. #define WD2        0xb9
  226. /*********************************************************************************************
  227. //用于STC11/10xx系列单片机时选择//
  228. sfr IAP_DATA    = 0xC2; //STC11xx系列单片机的EEPRON操作地址是0xc2(以下类推)
  229. sfr IAP_ADDRH   = 0xC3;
  230. sfr IAP_ADDRL   = 0xC4;
  231. sfr IAP_CMD     = 0xC5;
  232. sfr IAP_TRIG    = 0xC6;
  233. sfr IAP_CONTR   = 0xC7;
  234. #define WD1        0x5a        //使用STC11xx系列单片机时,先写入0x5a,然写入0xa5
  235. #define WD2        0xa5
  236. /*********************************************************************************************/
  237. //定义Flash 操作等待时间及允许IAP/ISP/EEPROM 操作的常数//
  238. //#define ENABLE_ISP 0x80 //系统工作时钟<30MHz 时,对IAP_CONTR 寄存器设置此值
  239. //#define ENABLE_ISP 0x81 //系统工作时钟<24MHz 时,对IAP_CONTR 寄存器设置此值
  240. #define ENABLE_ISP 0x82 //系统工作时钟<20MHz 时,对IAP_CONTR 寄存器设置此值
  241. //#define ENABLE_ISP 0x83 //系统工作时钟<12MHz 时,对IAP_CONTR 寄存器设置此值
  242. //#define ENABLE_ISP 0x84 //系统工作时钟<6MHz 时,对IAP_CONTR 寄存器设置此值
  243. //#define ENABLE_ISP 0x85 //系统工作时钟<3MHz 时,对IAP_CONTR 寄存器设置此值
  244. //#define ENABLE_ISP 0x86 //系统工作时钟<2MHz 时,对IAP_CONTR 寄存器设置此值
  245. //#define ENABLE_ISP 0x87 //系统工作时钟<1MHz 时,对IAP_CONTR 寄存器设置此值
  246. /*********************************************************************************************/
  247. #define DEBUG_DATA               0x55  //存储在 EEPROM 单元的数值(用户可修改测试)
  248. #define DATA_FLASH_START_ADDRESS 0x00  //EEPROM存入地址(用户可修改测试)
  249. /*********************************************************************************************/
  250. union union_temp16
  251. {
  252.     INT16U un_temp16;
  253.     INT8U  un_temp8[2];
  254. }my_unTemp16;

  255. INT8U Byte_Read(INT16U add);              //读一字节,调用前需打开IAP 功能
  256. void Byte_Program(INT16U add, INT8U ch);  //字节编程,调用前需打开IAP 功能
  257. void Sector_Erase(INT16U add);            //擦除扇区
  258. void IAP_Disable();                       //关闭IAP 功能
  259. void Delay();
  260. /*********************************************************************************************/
  261. void main (void)
  262. {
  263.     INT16U eeprom_address;
  264.     INT8U  read_eeprom;

  265.     P1 = 0xF0;                            //演示程序开始,让 P1[3:0] 控制的灯亮
  266.     Delay();                              //延时
  267.     P1 = 0x0F;                            //演示程序开始,让 P1[7:4] 控制的灯亮
  268.     Delay()    ;                          //延时

  269.     //将EEPROM 测试起始地址单元的内容读出
  270.     eeprom_address = DATA_FLASH_START_ADDRESS;  //将测试起始地址送eeprom_address
  271.     read_eeprom = Byte_Read(eeprom_address);    //读EEPROM的值,存到read_eeprom

  272.     if (DEBUG_DATA == read_eeprom)
  273.     {   //数据是对的,亮  P1.7 控制的灯,然后在 P1 口上将 EEPROM 的数据显示出来
  274.         P1 = ~0x80;
  275.         Delay()    ;                            //延时
  276.         P1 = ~read_eeprom;
  277.     }
  278.     else
  279.     {   //数据是错的,亮 P1.3 控制的灯,然后在 P1 口上将 EEPROM 的数据显示出来
  280.         //再将该EEPROM所在的扇区整个擦除,将正确的数据写入后,亮 P1.5 控制的灯
  281.         P1 = ~0x08;
  282.         Delay()    ;                            //延时
  283.         P1 = ~read_eeprom;
  284.         Delay()    ;                            //延时

  285.         Sector_Erase(eeprom_address);           //擦除整个扇区
  286.         Byte_Program(eeprom_address, DEBUG_DATA);//将 DEBUG_DATA 写入 EEPROM

  287.         P1 = ~0x20;                 //熄灭 P1.3 控制的灯,亮 P1.5 控制的灯
  288.     }

  289.     while (1);                      //CPU 在此无限循环执行此句
  290. }
  291. /*********************************************************************************************/
  292. //读一字节,调用前需打开IAP 功能,入口:DPTR = 字节地址,返回:A = 读出字节
  293. INT8U Byte_Read(INT16U add)
  294. {
  295.     IAP_DATA = 0x00;
  296.     IAP_CONTR = ENABLE_ISP;         //打开IAP 功能, 设置Flash 操作等待时间
  297.     IAP_CMD = 0x01;                 //IAP/ISP/EEPROM 字节读命令

  298.     my_unTemp16.un_temp16 = add;
  299.     IAP_ADDRH = my_unTemp16.un_temp8[0];    //设置目标单元地址的高8 位地址
  300.     IAP_ADDRL = my_unTemp16.un_temp8[1];    //设置目标单元地址的低8 位地址

  301.     //EA = 0;
  302.     IAP_TRIG = WD1;   //先送 WD1,再送WD2 到ISP/IAP 触发寄存器,每次都需如此
  303.     IAP_TRIG = WD2;   //送完WD2 后,ISP/IAP 命令立即被触发起动
  304.     _nop_();
  305.     //EA = 1;
  306.     IAP_Disable();  //关闭IAP 功能, 清相关的特殊功能寄存器,使CPU 处于安全状态,
  307.                     //一次连续的IAP 操作完成之后建议关闭IAP 功能,不需要每次都关
  308.     return (IAP_DATA);
  309. }
  310. /*********************************************************************************************/
  311. //字节编程,调用前需打开IAP 功能,入口:DPTR = 字节地址, A= 须编程字节的数据
  312. void Byte_Program(INT16U add, INT8U ch)
  313. {
  314.     IAP_CONTR = ENABLE_ISP;         //打开 IAP 功能, 设置Flash 操作等待时间
  315.     IAP_CMD = 0x02;                 //IAP/ISP/EEPROM 字节编程命令

  316.     my_unTemp16.un_temp16 = add;
  317.     IAP_ADDRH = my_unTemp16.un_temp8[0];    //设置目标单元地址的高8 位地址
  318.     IAP_ADDRL = my_unTemp16.un_temp8[1];    //设置目标单元地址的低8 位地址

  319.     IAP_DATA = ch;                  //要编程的数据先送进IAP_DATA 寄存器
  320.     //EA = 0;
  321.     IAP_TRIG = WD1;   //先送 WD1,再送WD2 到ISP/IAP 触发寄存器,每次都需如此
  322.     IAP_TRIG = WD2;   //送完WD2 后,ISP/IAP 命令立即被触发起动
  323.     _nop_();
  324.     //EA = 1;
  325.     IAP_Disable();  //关闭IAP 功能, 清相关的特殊功能寄存器,使CPU 处于安全状态,
  326.                     //一次连续的IAP 操作完成之后建议关闭IAP 功能,不需要每次都关
  327. }
  328. /*********************************************************************************************/
  329. //擦除扇区, 入口:DPTR = 扇区地址
  330. void Sector_Erase(INT16U add)
  331. {
  332.     IAP_CONTR = ENABLE_ISP;         //打开IAP 功能, 设置Flash 操作等待时间
  333.     IAP_CMD = 0x03;                 //IAP/ISP/EEPROM 扇区擦除命令

  334.     my_unTemp16.un_temp16 = add;
  335.     IAP_ADDRH = my_unTemp16.un_temp8[0];    //设置目标单元地址的高8 位地址
  336.     IAP_ADDRL = my_unTemp16.un_temp8[1];    //设置目标单元地址的低8 位地址

  337.     //EA = 0;
  338.     IAP_TRIG = WD1;   //先送 WD1,再送WD2 到ISP/IAP 触发寄存器,每次都需如此
  339.     IAP_TRIG = WD2;   //送完WD2 后,ISP/IAP 命令立即被触发起动
  340.     _nop_();
  341.     //EA = 1;
  342.     IAP_Disable();  //关闭IAP 功能, 清相关的特殊功能寄存器,使CPU 处于安全状态,
  343.                     //一次连续的IAP 操作完成之后建议关闭IAP 功能,不需要每次都关
  344. }
  345. /*********************************************************************************************/
  346. void IAP_Disable()
  347. {
  348.     //关闭IAP 功能, 清相关的特殊功能寄存器,使CPU 处于安全状态,
  349.     //一次连续的IAP 操作完成之后建议关闭IAP 功能,不需要每次都关
  350.     IAP_CONTR = 0;      //关闭IAP 功能
  351.     IAP_CMD   = 0;      //清命令寄存器,使命令寄存器无命令,此句可不用
  352.     IAP_TRIG  = 0;      //清命令触发寄存器,使命令触发寄存器无触发,此句可不用
  353.     IAP_ADDRH = 0;
  354.     IAP_ADDRL = 0;
  355. }
  356. /*********************************************************************************************/
  357. void Delay() //延时程序
  358. {
  359.     INT8U i;
  360.     INT16U d=5000;
  361.     while (d--)
  362.     {
  363.         i=255;
  364.         while (i--);
  365.     }
  366. }




复制代码

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

回复

使用道具 举报

ID:1 发表于 2018-11-6 18:46 | 显示全部楼层
补全原理图或者详细说明一下电路连接即可获得100+黑币
回复

使用道具 举报

ID:350104 发表于 2018-11-8 11:57 | 显示全部楼层
admin 发表于 2018-11-6 18:46
补全原理图或者详细说明一下电路连接即可获得100+黑币

这个是模板 万能使用 只要结合自己的电路修改相应的端口就可以了 很方便使用的
回复

使用道具 举报

ID:350104 发表于 2018-11-8 15:00 | 显示全部楼层
admin 发表于 2018-11-6 18:46
补全原理图或者详细说明一下电路连接即可获得100+黑币

这个是万能编程模板 只要根据自己的电路图 改改端口就能用
回复

使用道具 举报

ID:399179 发表于 2018-11-8 18:26 来自手机 | 显示全部楼层
感谢分享!
回复

使用道具 举报

ID:66287 发表于 2018-11-9 08:59 | 显示全部楼层
是有用的东东,谢谢分享!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表