STC - 官方库函数 - 串口操作修改
创始人
2024-04-02 02:31:10
0

文章目录

    • STC - 官方库函数 - 串口操作修改
    • 概述
    • 调试环境
    • 修改完的STC库串口操作
    • main.c
    • STC15Fxxxx.H
    • USART.h
    • USART.C
    • 总结
    • END

STC - 官方库函数 - 串口操作修改

概述

STC15官方库为 STC15-SOFTWARE-LIB-V1.0.rar, 解开后的文件夹为 STC15系列库函数与例程测试版V2.0.

板子做好了, 在用STC官方库函数写一个出厂测试程序. 写好之后, 只要烧录一个出厂测试程序, 就可以通过半自动测试, 很快能知道焊好的板子元件功能是否正常. 如果不正常, 是哪个元件的操作不正常. 这个时间划算.

刚开个头, 第一步是将下位机的信息上报到PC机的串口助手.
但是发现官方库函数的实现有点问题. 将全局buffer sprintf之后, 用串口发送到上位机, 看到的是乱码. 不使用sprintf就正常.
刚开始排查就以为是C51使用sprintf有特殊的地方, 去看前面踩过坑的同学的笔记.
但是我这情况和他们不一样啊. 我sprintf之后的buffer, 丢到watch窗口是正常的.
继续查STC库串口发送的实现, 发现点问题.
STC库实现, 弄了一个发送缓冲区, 发送时, 丢到发送缓冲区就不管了. 如果连续发送大段的文本, 超过缓冲区的大小, 就从buffer[0]开始循环堆数据. 这就导致了送到上位机的数据是不对的. 如果覆盖到汉字部分(汉字只剩下半部分), 就有可能出现乱码.

下位机的收发都是有应答的才对, 不可能那么小的缓冲区就随时丢进去, 也不管发送的原始信息是否发送完. 这样不好. 失去了发送的正确性.
改成了发送一个字符完成, 才发送下一个字符. 每次发送的内容, 都是阻塞发送, 发送任务完成后才离开.
接收不用改, 接收是有缓冲区的, 是靠超时来判断是否接收完. 接收内容一般是命令, 比较短. 可以放到缓冲区里面来.
如果接收的内容比较长, e.g. 升级的2进制内容, 那就需要有收发应答, 不能无脑的一直接收或一直发送.

STC官方库是一个测试版, 2015年以后就没有再修改过了. 估计每个公司都有成熟实现, 所以官方也不怎么上心整理库实现.
官方库的整体架子挺好的, 已经将寄存器操作封装的挺好的了. 估计官方也不知道该怎么升级改进这个库了(已经这么优秀了…).
可以拿官方库为蓝本, 将不适合自己的地方或有错误的地方改掉. 工作量不大.

修正完串口实现后, sprintf正常用, 没特别的.
大段, 连续的文本通过串口上传到上位机, 没看到丢失文本或乱码的情况. 改的还行.

前段时间去查资料, github上已经有大神上传了自己的STC15的库, 不止一个大神的库.
但是这个库本身就比较简单(主要是封装寄存器操作的细节, 这个STC官方已经做的很好了, 剩下的都是一些小bug), 用别人的库不如自己修正, 工作量不大, 理解的还深刻(以后有未知MCU, 如果只有datasheet上的寄存器描述, 可以自己尝试也封装一个库实现), 还适合自己用.

调试环境

MDK5(keil C51)

修改完的STC库串口操作

main.c

这里是测试逻辑, 用来上传大段文本到上位机的串口助手
用到了sprintf格式化buffer, 正常用就好, 没遇到坑, 可能还没遇到呢.

// @file main.c// --------------------------------------------------------------------------------
// 头文件包含
// --------------------------------------------------------------------------------// 不能包含 STC15F2K60S2.h, 即使是指定了一个不存在的 STC15F2K60S2.h
// 如果在指定目录下找不到 STC15F2K60S2.h, 也会去MDK5-C51目录下找
// 会和config.h中的STC15Fxxxx.H 中的寄存器定义冲突, 导致编译报错.
// #include "stc/STC15F2K60S2.h" // 包含工程目录下的.h// 如果使用STC库方式编程, 包含config.h, 不用再包含 STC*.h(e.g. STC15F2K60S2.h)
#include "stc/config.h"#include "stc/usart.h"
#include "stc/delay.h"#include  // for sprintf
#include  // for memset// 为了防止不调用所有库中的函数引起的编译警告, 只应在左面板的stc节点下包含必须的.c// --------------------------------------------------------------------------------
// 宏定义
// --------------------------------------------------------------------------------
#define TRUE 1
#define FALSE 0
#define LINE_60 "------------------------------------------------------------"// --------------------------------------------------------------------------------
// 全局变量定义
// --------------------------------------------------------------------------------
// 在这里定义一个128 bytes的buffer, 编译时, keil C51 经常报错, 将变量移动到非main.c中定义, 然后再非main.c的.h中用extern 声明变量.
// 好像不是在这定义全局变量的事情, 有时编译报错, 有时单步调试刚进入main时报错, 可能是keilC51本身的问题.// --------------------------------------------------------------------------------
// 函数声明
// --------------------------------------------------------------------------------
void Hardware_init(void);
void UART1_init(void);
void UART2_init(void);
void process_uart_cmd(void);
void disp_app_help_on_uart1(void);// --------------------------------------------------------------------------------
// 函数实现
// --------------------------------------------------------------------------------
int main(void)
{Hardware_init();PrintString1("me - STC15实验箱4 - 硬件出厂测试程序\r\n");disp_app_help_on_uart1();do {// process_uart_cmd(); // 这是阻塞的在等串口命令, 先不调用// testdisp_app_help_on_uart1(); // 不停的串口输出大段的文本, 看看有没有问题// 串口输出没问题, 挺好的} while (1);// return 0;
}void disp_app_help_on_uart1(void)
{memset(&g_tmp_buf[0], 0, sizeof(g_tmp_buf));sprintf(g_tmp_buf, "%s\r\n", LINE_60); // sprintf正常用就好, 挺正常的.PrintString1(g_tmp_buf);PrintString1("串口命令列表\r\n");memset(g_tmp_buf, 0, sizeof(g_tmp_buf));sprintf(g_tmp_buf, "%s\r\n", LINE_60);PrintString1(g_tmp_buf);PrintString1("1. cmd_test_key\r\n");PrintString1("2. cmd_test_Led\r\n");PrintString1("3. cmd_test_xram\r\n");PrintString1("4. cmd_test_e2prom\r\n");PrintString1("5. cmd_test_pm25\r\n");memset(g_tmp_buf, 0, sizeof(g_tmp_buf));sprintf(g_tmp_buf, "%s\r\n", LINE_60);PrintString1(g_tmp_buf);
}void process_uart_cmd(void)
{u8 i = 0;while (1){delay_ms(1);if(COM1.RX_TimeOut > 0)		//超时计数{if(--COM1.RX_TimeOut == 0){if(COM1.RX_Cnt > 0){for(i=0; iTX1_write2buff(RX1_Buffer[i]);	//收到的数据原样返回}}COM1.RX_Cnt = 0;}}}	
}void Hardware_init(void)
{EA = 0; // 总中断 - 关UART1_init();UART2_init();EA = 1; // 总中断 - 开// 在总中断开之后, 才可以操作和中断相关的操作. e.g. 串口打印// 否则需要等进中断才能设置的标志, 就会死等在那里PrintString1("COM1 - 初始化完成(9600/N/8/1)\r\n");PrintString2("COM2 - 初始化完成(115200/N/8/1)\r\n");
}void UART1_init(void)
{COMx_InitDefine		COMx_InitStructure;					//结构定义ES = 0; // 串行中断 - 关// COM1 9600/N/8/1COMx_InitStructure.UART_Mode      = UART_8bit_BRTx;		//模式,       UART_ShiftRight,UART_8bit_BRTx,UART_9bit,UART_9bit_BRTxCOMx_InitStructure.UART_BRT_Use   = BRT_Timer1;			//使用波特率,   BRT_Timer1, BRT_Timer2 (注意: 串口2固定使用BRT_Timer2)COMx_InitStructure.UART_BaudRate  = 9600ul;			//波特率, 一般 110 ~ 115200COMx_InitStructure.Morecommunicate = DISABLE; //多机通讯允许, ENABLE,DISABLECOMx_InitStructure.UART_RxEnable  = ENABLE;				//接收允许,   ENABLE或DISABLECOMx_InitStructure.BaudRateDouble = DISABLE;			//波特率加倍, ENABLE或DISABLECOMx_InitStructure.UART_Interrupt = ENABLE;				//中断允许,   ENABLE或DISABLECOMx_InitStructure.UART_Polity    = PolityLow;			//中断优先级, PolityLow,PolityHighCOMx_InitStructure.UART_P_SW      = UART1_SW_P16_P17;	//切换端口,   UART1_SW_P30_P31,UART1_SW_P36_P37,UART1_SW_P16_P17(必须使用内部时钟)COMx_InitStructure.UART_RXD_TXD_Short = DISABLE;		//内部短路RXD与TXD, 做中继, ENABLE,DISABLEUSART_Configuration(USART1, &COMx_InitStructure);		//初始化串口1 USART1,USART2ES = 1; // 串行中断 - 开}void UART2_init(void)
{COMx_InitDefine		COMx_InitStructure;					//结构定义ES = 0; // 串行中断 - 关// COM2 115200/N/8/1COMx_InitStructure.UART_Mode      = UART_8bit_BRTx;		//模式,       UART_ShiftRight,UART_8bit_BRTx,UART_9bit,UART_9bit_BRTxCOMx_InitStructure.UART_BRT_Use   = BRT_Timer2;			//使用波特率,   BRT_Timer1, BRT_Timer2 (注意: 串口2固定使用BRT_Timer2)COMx_InitStructure.UART_BaudRate  = 115200ul;			//波特率,     110 ~ 115200COMx_InitStructure.Morecommunicate = DISABLE; //多机通讯允许, ENABLE,DISABLECOMx_InitStructure.UART_RxEnable  = ENABLE;				//接收允许,   ENABLE或DISABLECOMx_InitStructure.BaudRateDouble = DISABLE;			//波特率加倍, ENABLE或DISABLECOMx_InitStructure.UART_Interrupt = ENABLE;				//中断允许,   ENABLE或DISABLECOMx_InitStructure.UART_Polity    = PolityLow;			//中断优先级, PolityLow,PolityHighCOMx_InitStructure.UART_P_SW      = UART2_SW_P46_P47;	//切换端口,   UART2_SW_P10_P11,UART2_SW_P46_P47COMx_InitStructure.UART_RXD_TXD_Short = DISABLE;		//内部短路RXD与TXD, 做中继, ENABLE,DISABLEUSART_Configuration(USART2, &COMx_InitStructure);		//初始化串口2 USART1,USART2ES = 1; // 串行中断 - 开}

STC15Fxxxx.H

官方有2个宏没有括号包围起来, 可能有点问题, 改了一下.

#ifndef	_STC15Fxxxx_H
#define	_STC15Fxxxx_H#include /*  BYTE Registers  */
sfr P0   = 0x80;
sfr SP   = 0x81;
sfr DPL  = 0x82;
sfr DPH  = 0x83;
sfr	S4CON = 0x84;
sfr	S4BUF = 0x85;
sfr PCON = 0x87;sfr TCON = 0x88;
sfr TMOD = 0x89;
sfr TL0  = 0x8A;
sfr TL1  = 0x8B;
sfr TH0  = 0x8C;
sfr TH1  = 0x8D;
sfr	AUXR = 0x8E;
sfr WAKE_CLKO = 0x8F;
sfr INT_CLKO = 0x8F;
sfr	AUXR2    = 0x8F;sfr RL_TL0  = 0x8A;
sfr RL_TL1  = 0x8B;
sfr RL_TH0  = 0x8C;
sfr RL_TH1  = 0x8D;sfr P1   = 0x90;
sfr P1M1 = 0x91;	//P1M1.n,P1M0.n 	=00--->Standard,	01--->push-pull		实际上1T的都一样
sfr P1M0 = 0x92;	//					=10--->pure input,	11--->open drain
sfr P0M1 = 0x93;	//P0M1.n,P0M0.n 	=00--->Standard,	01--->push-pull
sfr P0M0 = 0x94;	//					=10--->pure input,	11--->open drain
sfr P2M1 = 0x95;	//P2M1.n,P2M0.n 	=00--->Standard,	01--->push-pull
sfr P2M0 = 0x96;	//					=10--->pure input,	11--->open drain
sfr CLK_DIV = 0x97;
sfr PCON2   = 0x97;sfr SCON  = 0x98;
sfr SBUF  = 0x99;
sfr S2CON = 0x9A;	//
sfr S2BUF = 0x9B;	//
sfr P1ASF = 0x9D;	//只写,模拟输入(AD或LVD)选择sfr P2    = 0xA0;
sfr BUS_SPEED = 0xA1;
sfr AUXR1 = 0xA2;
sfr P_SW1 = 0xA2;sfr IE    = 0xA8;
sfr SADDR = 0xA9;
sfr WKTCL = 0xAA;	//唤醒定时器低字节
sfr WKTCH = 0xAB;	//唤醒定时器高字节
sfr	S3CON = 0xAC;
sfr S3BUF = 0xAD;
sfr IE2   = 0xAF;	//STC12C5A60S2系列sfr P3    = 0xB0;
sfr P3M1  = 0xB1;	//P3M1.n,P3M0.n 	=00--->Standard,	01--->push-pull
sfr P3M0  = 0xB2;	//					=10--->pure input,	11--->open drain
sfr P4M1  = 0xB3;	//P4M1.n,P4M0.n 	=00--->Standard,	01--->push-pull
sfr P4M0  = 0xB4;	//					=10--->pure input,	11--->open drain
sfr IP2   = 0xB5;	//STC12C5A60S2系列
sfr IPH2  = 0xB6;	//STC12C5A60S2系列
sfr IPH   = 0xB7;sfr IP        = 0xB8;
sfr SADEN     = 0xB9;
sfr	P_SW2     = 0xBA;
sfr ADC_CONTR = 0xBC;	//带AD系列
sfr ADC_RES   = 0xBD;	//带AD系列
sfr ADC_RESL  = 0xBE;	//带AD系列sfr P4        = 0xC0;
sfr WDT_CONTR = 0xC1;
sfr IAP_DATA  = 0xC2;
sfr IAP_ADDRH = 0xC3;
sfr IAP_ADDRL = 0xC4;
sfr IAP_CMD   = 0xC5;
sfr IAP_TRIG  = 0xC6;
sfr IAP_CONTR = 0xC7;sfr ISP_DATA  = 0xC2;
sfr ISP_ADDRH = 0xC3;
sfr ISP_ADDRL = 0xC4;
sfr ISP_CMD   = 0xC5;
sfr ISP_TRIG  = 0xC6;
sfr ISP_CONTR = 0xC7;sfr P5     = 0xC8;	//
sfr P5M1   = 0xC9;	//	P5M1.n,P5M0.n 	=00--->Standard,	01--->push-pull
sfr P5M0   = 0xCA;	//					=10--->pure input,	11--->open drain
sfr P6M1   = 0xCB;	//	P5M1.n,P5M0.n 	=00--->Standard,	01--->push-pull
sfr P6M0   = 0xCC;	//					=10--->pure input,	11--->open drain
sfr SPSTAT = 0xCD;	//
sfr SPCTL  = 0xCE;	//
sfr SPDAT  = 0xCF;	//sfr PSW  = 0xD0;
sfr	T4T3M = 0xD1;
sfr	T4H  = 0xD2;
sfr	T4L  = 0xD3;
sfr	T3H  = 0xD4;
sfr	T3L  = 0xD5;
sfr	T2H  = 0xD6;
sfr	T2L  = 0xD7;sfr	TH4  = 0xD2;
sfr	TL4  = 0xD3;
sfr	TH3  = 0xD4;
sfr	TL3  = 0xD5;
sfr	TH2  = 0xD6;
sfr	TL2  = 0xD7;sfr	RL_T4H  = 0xD2;
sfr	RL_T4L  = 0xD3;
sfr	RL_T3H  = 0xD4;
sfr	RL_T3L  = 0xD5;
sfr	RL_T2H  = 0xD6;
sfr	RL_T2L  = 0xD7;sfr CCON = 0xD8;	//
sfr CMOD = 0xD9;	//
sfr CCAPM0 = 0xDA;	//PCA模块0的工作模式寄存器。
sfr CCAPM1 = 0xDB;	//PCA模块1的工作模式寄存器。
sfr CCAPM2 = 0xDC;	//PCA模块2的工作模式寄存器。sfr ACC    = 0xE0;
sfr	P7M1   = 0xE1;
sfr	P7M0   = 0xE2;sfr	P6     = 0xE8;
sfr CL     = 0xE9;	//
sfr CCAP0L = 0xEA;	//PCA模块0的捕捉/比较寄存器低8位。
sfr CCAP1L = 0xEB;	//PCA模块1的捕捉/比较寄存器低8位。
sfr CCAP2L = 0xEC;	//PCA模块2的捕捉/比较寄存器低8位。sfr B      = 0xF0;
sfr PCA_PWM0 = 0xF2;	//PCA模块0 PWM寄存器。
sfr PCA_PWM1 = 0xF3;	//PCA模块1 PWM寄存器。
sfr PCA_PWM2 = 0xF4;	//PCA模块2 PWM寄存器。sfr	P7     = 0xF8;
sfr CH     = 0xF9;
sfr CCAP0H = 0xFA;		//PCA模块0的捕捉/比较寄存器高8位。
sfr CCAP1H = 0xFB;		//PCA模块1的捕捉/比较寄存器高8位。
sfr CCAP2H = 0xFC;		//PCA模块2的捕捉/比较寄存器高8位。/*  BIT Registers  */
/*  PSW   */
sbit CY   = PSW^7;
sbit AC   = PSW^6;
sbit F0   = PSW^5;
sbit RS1  = PSW^4;
sbit RS0  = PSW^3;
sbit OV   = PSW^2;
sbit F1   = PSW^1;
sbit P    = PSW^0;/*  TCON  */
sbit TF1  = TCON^7;	//定时器1溢出中断标志位
sbit TR1  = TCON^6;	//定时器1运行控制位
sbit TF0  = TCON^5;	//定时器0溢出中断标志位
sbit TR0  = TCON^4;	//定时器0运行控制位
sbit IE1  = TCON^3;	//外中断1标志位
sbit IT1  = TCON^2;	//外中断1信号方式控制位,1:下降沿中断,0:上升下降均中断。
sbit IE0  = TCON^1;	//外中断0标志位
sbit IT0  = TCON^0;	//外中断0信号方式控制位,1:下降沿中断,0:上升下降均中断。/*  P0  */
sbit  P00 = P0^0;
sbit  P01 = P0^1;
sbit  P02 = P0^2;
sbit  P03 = P0^3;
sbit  P04 = P0^4;
sbit  P05 = P0^5;
sbit  P06 = P0^6;
sbit  P07 = P0^7;/*  P1  */
sbit  P10 = P1^0;
sbit  P11 = P1^1;
sbit  P12 = P1^2;
sbit  P13 = P1^3;
sbit  P14 = P1^4;
sbit  P15 = P1^5;
sbit  P16 = P1^6;
sbit  P17 = P1^7;sbit  RXD2      = P1^0;
sbit  TXD2      = P1^1;
sbit  CCP1      = P1^0;
sbit  CCP0      = P1^1;
sbit  SPI_SS    = P1^2;
sbit  SPI_MOSI  = P1^3;
sbit  SPI_MISO  = P1^4;
sbit  SPI_SCLK  = P1^5;sbit  SPI_SS_2    = P2^4;
sbit  SPI_MOSI_2  = P2^3;
sbit  SPI_MISO_2  = P2^2;
sbit  SPI_SCLK_2  = P2^1;sbit  SPI_SS_3    = P5^4;
sbit  SPI_MOSI_3  = P4^0;
sbit  SPI_MISO_3  = P4^1;
sbit  SPI_SCLK_3  = P4^3;/*  P2  */
sbit  P20 = P2^0;
sbit  P21 = P2^1;
sbit  P22 = P2^2;
sbit  P23 = P2^3;
sbit  P24 = P2^4;
sbit  P25 = P2^5;
sbit  P26 = P2^6;
sbit  P27 = P2^7;/*  P3  */
sbit  P30 = P3^0;
sbit  P31 = P3^1;
sbit  P32 = P3^2;
sbit  P33 = P3^3;
sbit  P34 = P3^4;
sbit  P35 = P3^5;
sbit  P36 = P3^6;
sbit  P37 = P3^7;sbit RXD  = P3^0;
sbit TXD  = P3^1;
sbit INT0 = P3^2;
sbit INT1 = P3^3;
sbit T0   = P3^4;
sbit T1   = P3^5;
sbit WR   = P3^6;
sbit RD   = P3^7;
sbit CCP2  = P3^7;sbit CLKOUT0   = P3^5;
sbit CLKOUT1   = P3^4;/*  P4  */
sbit  P40 = P4^0;
sbit  P41 = P4^1;
sbit  P42 = P4^2;
sbit  P43 = P4^3;
sbit  P44 = P4^4;
sbit  P45 = P4^5;
sbit  P46 = P4^6;
sbit  P47 = P4^7;/*  P5  */
sbit  P50 = P5^0;
sbit  P51 = P5^1;
sbit  P52 = P5^2;
sbit  P53 = P5^3;
sbit  P54 = P5^4;
sbit  P55 = P5^5;
sbit  P56 = P5^6;
sbit  P57 = P5^7;/*  SCON  */
sbit SM0  = SCON^7;	//SM0/FE		SM0 SM1 = 00 ~ 11: 方式0~3
sbit SM1  = SCON^6;	//
sbit SM2  = SCON^5;	//多机通讯
sbit REN  = SCON^4;	//接收允许
sbit TB8  = SCON^3;	//发送数据第8位
sbit RB8  = SCON^2;	//接收数据第8位
sbit TI   = SCON^1;	//发送中断标志位
sbit RI   = SCON^0;	//接收中断标志位/*  IE   */
sbit EA   = IE^7;	//中断允许总控制位
sbit ELVD = IE^6;	//低压监测中断允许位
sbit EADC = IE^5;	//ADC 中断 允许位
sbit ES   = IE^4;	//串行中断 允许控制位
sbit ET1  = IE^3;	//定时中断1允许控制位
sbit EX1  = IE^2;	//外部中断1允许控制位
sbit ET0  = IE^1;	//定时中断0允许控制位
sbit EX0  = IE^0;	//外部中断0允许控制位/*  IP   */ 
/*
sbit PPCA = IP^7;	//PCA 中断 优先级设定位
sbit PLVD = IP^6; 	//低压中断 优先级设定位
sbit PADC = IP^5; 	//ADC 中断 优先级设定位
sbit PS   = IP^4;	//串行中断0优先级设定位
sbit PT1  = IP^3;	//定时中断1优先级设定位
sbit PX1  = IP^2;	//外部中断1优先级设定位
sbit PT0  = IP^1;	//定时中断0优先级设定位
sbit PX0  = IP^0;	//外部中断0优先级设定位
*/sbit ACC0 = ACC^0;
sbit ACC1 = ACC^1;
sbit ACC2 = ACC^2;
sbit ACC3 = ACC^3;
sbit ACC4 = ACC^4;
sbit ACC5 = ACC^5;
sbit ACC6 = ACC^6;
sbit ACC7 = ACC^7;sbit B0 = B^0;
sbit B1 = B^1;
sbit B2 = B^2;
sbit B3 = B^3;
sbit B4 = B^4;
sbit B5 = B^5;
sbit B6 = B^6;
sbit B7 = B^7;//							7     6     5    4    3    2    1     0    Reset Value
//sfr IE2       = 0xAF;		-     -     -    -    -    -   ESPI  ES2   0000,0000B	//Auxiliary Interrupt   
#define		SPI_INT_ENABLE()		IE2 |=  2	//允许SPI中断
#define		SPI_INT_DISABLE()		IE2 &= ~2	//允许SPI中断
#define		UART2_INT_ENABLE()		IE2 |=  1	//允许串口2中断
#define		UART2_INT_DISABLE()		IE2 &= ~1	//允许串口2中断//                                          7     6     5    4    3    2    1    0    Reset Value
//sfr IP      = 0xB8; //中断优先级低位      PPCA  PLVD  PADC  PS   PT1  PX1  PT0  PX0   0000,0000
//--------
sbit PPCA	= IP^7;	//PCA 模块中断优先级
sbit PLVD	= IP^6;	//低压监测中断优先级
sbit PADC	= IP^5;	//ADC 中断优先级
sbit PS   	= IP^4;	//串行中断0优先级设定位
sbit PT1	= IP^3;	//定时中断1优先级设定位
sbit PX1	= IP^2;	//外部中断1优先级设定位
sbit PT0	= IP^1;	//定时中断0优先级设定位
sbit PX0	= IP^0;	//外部中断0优先级设定位//                                           7      6      5     4     3     2    1     0        Reset Value
//sfr IPH   = 0xB7; //中断优先级高位       PPCAH  PLVDH  PADCH  PSH  PT1H  PX1H  PT0H  PX0H   0000,0000
//sfr IP2   = 0xB5; //                       -      -      -     -     -     -   PSPI   PS2   xxxx,xx00
//sfr IPH2  = 0xB6; //                       -      -      -     -     -     -   PSPIH  PS2H  xxxx,xx00
#define		PPCAH	0x80
#define		PLVDH	0x40
#define		PADCH	0x20
#define		PSH		0x10
#define		PT1H	0x08
#define		PX1H	0x04
#define		PT0H	0x02
#define		PX0H	0x01#define		PCA_InterruptFirst()	PPCA = 1
#define		LVD_InterruptFirst()	PLVD = 1
#define		ADC_InterruptFirst()	PADC = 1
#define		UART1_InterruptFirst()	PS   = 1
#define		Timer1_InterruptFirst()	PT1  = 1
#define		INT1_InterruptFirst()	PX1  = 1
#define		Timer0_InterruptFirst()	PT0  = 1
#define		INT0_InterruptFirst()	PX0  = 1/*************************************************************************************************/
#define		S1_DoubleRate()		PCON |= 0x80
#define		S1_SHIFT()			SCON &= 0x3f
#define		S1_8bit()			SCON |= 0x40
#define		S1_9bit()			SCON |= 0xc0
#define		S1_RX_Enable()		SCON |= 0x10
#define		S1_USE_P30P31()		P_SW1 &=  ~0xc0					//UART1 使用P30 P31口	默认
#define		S1_USE_P36P37()		P_SW1 = (P_SW1 & ~0xc0) | 0x40	//UART1 使用P36 P37口
#define		S1_USE_P16P17()		P_SW1 = (P_SW1 & ~0xc0) | 0x80	//UART1 使用P16 P17口
#define		S1_TXD_RXD_SHORT()	PCON2 |= (1<<4)	//将TXD与RXD连接中继输出
#define		S1_TXD_RXD_OPEN()	PCON2 |= (1<<4)	//将TXD与RXD连接中继断开	默认
#define 	S1_BRT_UseTimer2()	AUXR |=  1;
#define 	S1_BRT_UseTimer1()	AUXR &= ~1;//						  7      6      5      4      3      2     1     0        Reset Value
//sfr S2CON = 0x9A;		S2SM0    -    S2SM2  S2REN  S2TB8  S2RB8  S2TI  S2RI      00000000B		 //S2 Control#define		S2_8bit()			S2CON &= ~(1<<7)		//串口2模式0,8位UART,波特率 = 定时器2的溢出率 / 4
#define		S2_9bit()			S2CON |=  (1<<7)		//串口2模式1,9位UART,波特率 = 定时器2的溢出率 / 4
#define		S2_RX_Enable()		S2CON |=  (1<<4)		//允许串2接收#define		S2_MODE0()			S2CON &= ~(1<<7)		//串口2模式0,8位UART,波特率 = 定时器2的溢出率 / 4
#define		S2_MODE1()			S2CON |=  (1<<7)		//串口2模式1,9位UART,波特率 = 定时器2的溢出率 / 4
#define		S2_RX_EN()			S2CON |=  (1<<4)							//允许串2接收
#define		S2_RX_Disable()		S2CON &= ~(1<<4)							//禁止串2接收
#define		TI2					((S2CON & 2) != 0) // 这个宏, 需要用括号包围起来才靠谱
#define		RI2					((S2CON & 1) != 0) // 这个宏, 需要用括号包围起来才靠谱
#define		SET_TI2()			S2CON |=  2
#define		CLR_TI2()			S2CON &= ~2
#define		CLR_RI2()			S2CON &= ~1
#define		S2TB8_SET()			S2CON |=  8
#define		S2TB8_CLR()			S2CON &= ~8
#define		S2_Int_en()			IE2   |=  1		//串口2允许中断
#define		S2_USE_P10P11()		P_SW2 &= ~1		//UART2 使用P1口	默认
#define		S2_USE_P46P47()		P_SW2 |=  1		//UART2 使用P4口#define		S3_USE_P00P01()		P_SW2 &= ~2		//UART3 使用P0口	默认
#define		S3_USE_P50P51()		P_SW2 |=  2		//UART3 使用P5口
#define		S4_USE_P02P03()		P_SW2 &= ~4		//UART4 使用P0口	默认
#define		S4_USE_P52P53()		P_SW2 |=  4		//UART4 使用P5口/**********************************************************/#define		Timer0_16bitAutoReload()	TMOD &= ~0x03					//16位自动重装
#define		Timer0_16bit()				TMOD  = (TMOD & ~0x03) | 0x01	//16位
#define		Timer0_8bitAutoReload()		TMOD  = (TMOD & ~0x03) | 0x02	//8位自动重装
#define		Timer0_16bitAutoRL_NoMask()	TMOD |=  0x03		//16位自动重装不可屏蔽中断
#define		Timer0_AsCounterP32()		TMOD |=  4		//时器0用做计数器
#define		Timer0_AsTimer()			TMOD &= ~4		//时器0用做定时器
#define		Timer0_ExtControlP34()		TMOD |=  4		//时器0由外部INT0高电平允许定时计数
#define 	Timer0_Run()	 			TR0 = 1				//允许定时器0计数
#define 	Timer0_Stop()	 			TR0 = 0				//禁止定时器0计数
#define 	Timer0_InterruptEnable()	ET0 = 1				//允许Timer1中断.
#define 	Timer0_InterruptDisable()	ET0 = 0				//禁止Timer1中断.#define		Timer1_16bitAutoReload()	TMOD &= ~0x30					//16位自动重装
#define		Timer1_16bit()				TMOD  = (TMOD & ~0x30) | 0x10	//16位
#define		Timer1_8bitAutoReload()		TMOD  = (TMOD & ~0x30) | 0x20	//8位自动重装
#define		Timer1_16bitAutoRL_NoMask()	TMOD |=  0x30		//16位自动重装不可屏蔽中断
#define		Timer1_AsCounterP33()		TMOD |=  (1<<6)		//时器1用做计数器
#define		Timer1_AsTimer()			TMOD &= ~(1<<6)		//时器1用做定时器
#define		Timer1_ExtControlP35()		TMOD |=  (1<<7)		//时器1由外部INT1高电平允许定时计数
#define 	Timer1_Run()	 			TR1 = 1				//允许定时器1计数
#define 	Timer1_Stop()	 			TR1 = 0				//禁止定时器1计数
#define 	Timer1_InterruptEnable()	ET1 = 1				//允许Timer1中断.
#define 	Timer1_InterruptDisable()	ET1 = 0				//禁止Timer1中断.//						   7     6       5      4     3      2      1      0    Reset Value
//sfr AUXR  = 0x8E;		T0x12 T1x12 UART_M0x6  BRTR S2SMOD BRTx12 EXTRAM S1BRS  0000,0000	//Auxiliary Register #define 	Timer0_1T()					AUXR |=  (1<<7)	//Timer0 clodk = fo
#define 	Timer0_12T()				AUXR &= ~(1<<7)	//Timer0 clodk = fo/12	12分频,	default
#define 	Timer1_1T()					AUXR |=  (1<<6)	//Timer1 clodk = fo
#define 	Timer1_12T()				AUXR &= ~(1<<6)	//Timer1 clodk = fo/12	12分频,	default
#define		S1_M0x6()					AUXR |=  (1<<5)	//UART Mode0 Speed is 6x Standard
#define		S1_M0x1()					AUXR &= ~(1<<5)	//default,	UART Mode0 Speed is Standard
#define 	Timer2_Run()	 			AUXR |=  (1<<4)	//允许定时器2计数
#define 	Timer2_Stop()	 			AUXR &= ~(1<<4)	//禁止定时器2计数
#define		Timer2_AsCounterP31()		AUXR |=  (1<<3)	//时器2用做计数器
#define		Timer2_AsTimer()			AUXR &= ~(1<<3)	//时器2用做定时器
#define 	Timer2_1T()					AUXR |=  (1<<2)	//Timer0 clodk = fo
#define 	Timer2_12T()				AUXR &= ~(1<<2)	//Timer0 clodk = fo/12	12分频,	default
#define 	Timer2_InterruptEnable()	IE2  |=  (1<<2)	//允许Timer2中断.
#define 	Timer2_InterruptDisable()	IE2  &= ~(1<<2)	//禁止Timer2中断.#define 	ExternalRAM_enable()		AUXR |=  2		//允许外部XRAM,禁止使用内部1024RAM
#define 	InternalRAM_enable()		AUXR &= ~2		//禁止外部XRAM,允许使用内部1024RAM#define		T0_pulseP34_enable()		AUXR2 |=  1		//允许 T0 溢出脉冲在T0(P3.5)脚输出,Fck0 = 1/2 T0 溢出率,T0可以1T或12T。
#define		T0_pulseP34_disable()		AUXR2 &= ~1
#define		T1_pulseP35_enable()		AUXR2 |=  2		//允许 T1 溢出脉冲在T1(P3.4)脚输出,Fck1 = 1/2 T1 溢出率,T1可以1T或12T。
#define		T1_pulseP35_disable()		AUXR2 &= ~2
#define		T2_pulseP30_enable()		AUXR2 |=  4		//允许 T2 溢出脉冲在T1(P3.0)脚输出,Fck2 = 1/2 T2 溢出率,T2可以1T或12T。
#define		T2_pulseP30_disable()		AUXR2 &= ~4#define		T0_pulseP35(n)		ET0=0,Timer0_AsTimer(),Timer0_1T(),Timer0_16bitAutoReload(),TH0=(65536-(n/2+MAIN_Fosc/2)/(n))/256,TL0=(65536-(n/2+MAIN_Fosc/2)/(n))%256,AUXR2 |= bit0,TR0=1		//fx=fosc/(2*M)/n,  M=1 or M=12
#define		T1_pulseP34(n)		ET1=0,Timer1_AsTimer(),Timer1_1T(),Timer1_16bitAutoReload(),TH1=(65536-(n/2+MAIN_Fosc/2)/(n))/256,TL1=(65536-(n/2+MAIN_Fosc/2)/(n))%256,AUXR2 |= bit1,TR1=1		//fx=fosc/(2*M)/n,  M=1 or M=12
#define		T2_pulseP30(n)		Timer2_InterruptDisable(),Timer2_AsTimer(),Timer2_1T(),TH2=(65536-(n/2+MAIN_Fosc/2)/(n))/256,TL2=(65536-(n/2+MAIN_Fosc/2)/(n))%256,AUXR2 |= bit2,Timer2_Run()	//fx=fosc/(2*M)/n,  M=1 or M=12#define		Timer0_Load(n)		TH0 = (n) / 256,	TL0 = (n) % 256
#define		Timer1_Load(n)		TH1 = (n) / 256,	TL1 = (n) % 256
#define		Timer2_Load(n)		TH2 = (n) / 256,	TL2 = (n) % 256#define		Timer0_Load_us(n)	TH0=(65536-MainFosc_KHZ*(n)/1000)/256,TL0=(65536-MainFosc_KHZ*(n)/1000)%256
#define		Timer1_Load_us(n)	TH1=(65536-MainFosc_KHZ*(n)/1000)/256,TL1=(65536-MainFosc_KHZ*(n)/1000)%256
#define		Timer2_Load_us(n)	TH2=(65536-MainFosc_KHZ*(n)/1000)/256,TL2=(65536-MainFosc_KHZ*(n)/1000)%256//sfr WDT_CONTR = 0xC1; //Watch-Dog-Timer Control register
//                                      7     6     5      4       3      2   1   0     Reset Value
//                                  WDT_FLAG  -  EN_WDT CLR_WDT IDLE_WDT PS2 PS1 PS0    xx00,0000
#define D_WDT_FLAG			(1<<7)
#define D_EN_WDT			(1<<5)
#define D_CLR_WDT			(1<<4)	//auto clear
#define D_IDLE_WDT			(1<<3)	//WDT counter when Idle
#define D_WDT_SCALE_2		0
#define D_WDT_SCALE_4		1
#define D_WDT_SCALE_8		2		//T=393216*N/fo
#define D_WDT_SCALE_16		3
#define D_WDT_SCALE_32		4
#define D_WDT_SCALE_64		5
#define D_WDT_SCALE_128		6
#define D_WDT_SCALE_256		7#define	WDT_reset(n)	WDT_CONTR = D_EN_WDT + D_CLR_WDT + D_IDLE_WDT + (n)		//初始化WDT,喂狗//						  7     6      5    4     3      2    1     0     Reset Value
//sfr PCON   = 0x87;	SMOD  SMOD0  LVDF  POF   GF1    GF0   PD   IDL    0001,0000	 //Power Control 
//SMOD		//串口双倍速
//SMOD0
#define		LVDF		(1<<5)	//P4.6低压检测标志
//POF
//GF1
//GF0
//#define 	D_PD		2		//set 1, power down mode
//#define 	D_IDLE		1		//set 1, idle mode
#define		MCU_IDLE()			PCON |= 1	//MCU 进入 IDLE 模式
#define		MCU_POWER_DOWN()	PCON |= 2	//MCU 进入 睡眠 模式//sfr ISP_CMD   = 0xC5;
#define		ISP_STANDBY()	ISP_CMD = 0		//ISP空闲命令(禁止)
#define		ISP_READ()		ISP_CMD = 1		//ISP读出命令
#define		ISP_WRITE()		ISP_CMD = 2		//ISP写入命令
#define		ISP_ERASE()		ISP_CMD = 3		//ISP擦除命令//sfr ISP_TRIG  = 0xC6;
#define 	ISP_TRIG()	ISP_TRIG = 0x5A,	ISP_TRIG = 0xA5		//ISP触发命令//							  7    6    5      4    3    2    1     0    Reset Value
//sfr IAP_CONTR = 0xC7;		IAPEN SWBS SWRST CFAIL  -   WT2  WT1   WT0   0000,x000	//IAP Control Register
#define ISP_EN			(1<<7)
#define ISP_SWBS		(1<<6)
#define ISP_SWRST		(1<<5)
#define ISP_CMD_FAIL	(1<<4)
#define ISP_WAIT_1MHZ	7
#define ISP_WAIT_2MHZ	6
#define ISP_WAIT_3MHZ	5
#define ISP_WAIT_6MHZ	4
#define ISP_WAIT_12MHZ	3
#define ISP_WAIT_20MHZ	2
#define ISP_WAIT_24MHZ	1
#define ISP_WAIT_30MHZ	0#if (MAIN_Fosc >= 24000000L)#define		ISP_WAIT_FREQUENCY	ISP_WAIT_30MHZ
#elif (MAIN_Fosc >= 20000000L)#define		ISP_WAIT_FREQUENCY	ISP_WAIT_24MHZ
#elif (MAIN_Fosc >= 12000000L)#define		ISP_WAIT_FREQUENCY	ISP_WAIT_20MHZ
#elif (MAIN_Fosc >= 6000000L)#define		ISP_WAIT_FREQUENCY	ISP_WAIT_12MHZ
#elif (MAIN_Fosc >= 3000000L)#define		ISP_WAIT_FREQUENCY	ISP_WAIT_6MHZ
#elif (MAIN_Fosc >= 2000000L)#define		ISP_WAIT_FREQUENCY	ISP_WAIT_3MHZ
#elif (MAIN_Fosc >= 1000000L)#define		ISP_WAIT_FREQUENCY	ISP_WAIT_2MHZ
#else#define		ISP_WAIT_FREQUENCY	ISP_WAIT_1MHZ
#endif/* ADC Register */
//								7       6      5       4         3      2    1    0   Reset Value
//sfr ADC_CONTR = 0xBC;		ADC_POWER SPEED1 SPEED0 ADC_FLAG ADC_START CHS2 CHS1 CHS0 0000,0000	//AD 转换控制寄存器 
//sfr ADC_RES  = 0xBD;		ADCV.9 ADCV.8 ADCV.7 ADCV.6 ADCV.5 ADCV.4 ADCV.3 ADCV.2	  0000,0000	//A/D 转换结果高8位 
//sfr ADC_RESL = 0xBE;												  ADCV.1 ADCV.0	  0000,0000	//A/D 转换结果低2位
//sfr ADC_CONTR  = 0xBC;	//直接用MOV操作,不要用与或//sfr SPCTL  = 0xCE;	SPI控制寄存器
//   7       6       5       4       3       2       1       0    	Reset Value
//	SSIG	SPEN	DORD	MSTR	CPOL	CPHA	SPR1	SPR0		0x00#define	SPI_SSIG_None()		SPCTL |=  (1<<7)		//1: 忽略SS脚
#define	SPI_SSIG_Enable()	SPCTL &= ~(1<<7)		//0: SS脚用于决定主从机
#define	SPI_Enable()		SPCTL |=  (1<<6)		//1: 允许SPI
#define	SPI_Disable()		SPCTL &= ~(1<<6)		//0: 禁止SPI
#define	SPI_LSB_First()		SPCTL |=  (1<<5)		//1: LSB先发
#define	SPI_MSB_First()		SPCTL &= ~(1<<5)		//0: MSB先发
#define	SPI_Master()		SPCTL |=  (1<<4)		//1: 设为主机
#define	SPI_Slave()			SPCTL &= ~(1<<4)		//0: 设为从机
#define	SPI_SCLK_NormalH()	SPCTL |=  (1<<3)		//1: 空闲时SCLK为高电平
#define	SPI_SCLK_NormalL()	SPCTL &= ~(1<<3)		//0: 空闲时SCLK为低电平
#define	SPI_PhaseH()		SPCTL |=  (1<<2)		//1: 
#define	SPI_PhaseL()		SPCTL &= ~(1<<2)		//0: 
#define	SPI_Speed(n)		SPCTL = (SPCTL & ~3) | (n)	//设置速度, 0 -- fosc/4, 1 -- fosc/16, 2 -- fosc/64, 3 -- fosc/128//sfr SPDAT  = 0xCF; //SPI Data Register                                                     0000,0000
//sfr SPSTAT  = 0xCD;	//SPI状态寄存器
//   7       6      5   4   3   2   1   0    	Reset Value
//	SPIF	WCOL	-	-	-	-	-	-
#define	SPIF	0x80		//SPI传输完成标志。写入1清0。
#define	WCOL	0x40		//SPI写冲突标志。写入1清0。#define		SPI_USE_P12P13P14P15()	AUXR1 &= 0x0c	//将SPI切换到P12(SS) P13(MOSI) P14(MISO) P15(SCLK)(上电默认)。
#define		SPI_USE_P24P23P22P21()	AUXR1 = (AUXR1 & ~0x0c) | 0x04	//将SPI切换到P24(SS) P23(MOSI) P22(MISO) P21(SCLK)。
#define		SPI_USE_P54P40P41P43()	AUXR1 = (AUXR1 & ~0x0c) | 0x08	//将SPI切换到P54(SS) P40(MOSI) P41(MISO) P43(SCLK)。/*
;PCA_PWMn:    7       6     5   4   3   2     1       0
;			EBSn_1	EBSn_0	-	-	-	-	EPCnH	EPCnL
;B5-B2:		保留
;B1(EPCnH):	在PWM模式下,与CCAPnH组成9位数。
;B0(EPCnL):	在PWM模式下,与CCAPnL组成9位数。
*/
#define		PWM0_NORMAL()	PCA_PWM0 &= ~3				//PWM0正常输出(默认)
#define		PWM0_OUT_0()	PCA_PWM0 |=  3				//PWM0一直输出0
#define		PWM0_OUT_1()	PCA_PWM0 &= ~3, CCAP0H = 0;	//PWM0一直输出1#define		PWM1_NORMAL()	PCA_PWM1 &= ~3				//PWM0正常输出(默认)
#define		PWM1_OUT_0()	PCA_PWM1 |=  3				//PWM0一直输出0
#define		PWM1_OUT_1()	PCA_PWM1 &= ~3, CCAP1H = 0;	//PWM1一直输出1#define		PWM2_NORMAL()	PCA_PWM2 &= ~3				//PWM1正常输出(默认)
#define		PWM2_OUT_0()	PCA_PWM2 |=  3				//PWM2一直输出0
#define		PWM2_OUT_1()	PCA_PWM2 &= ~3, CCAP2H = 0;	//PWM2一直输出1//						7     6     5     4     3     2     1     0     Reset Value
//sfr CCON   = 0xD8;	CF    CR    -     -     -    CCF2  CCF1  CCF0   00xx,xx00	//PCA 控制寄存器。
sbit CCF0  = CCON^0;	//PCA 模块0中断标志,由硬件置位,必须由软件清0。
sbit CCF1  = CCON^1;	//PCA 模块1中断标志,由硬件置位,必须由软件清0。
sbit CCF2  = CCON^2;	//PCA 模块2中断标志,由硬件置位,必须由软件清0。
sbit CR    = CCON^6;	//1: 允许PCA计数器计数,必须由软件清0。
sbit CF    = CCON^7;	//PCA计数器溢出(CH,CL由FFFFH变为0000H)标志。PCA计数器溢出后由硬件置位,必须由软件清0。//					 7     6     5     4     3     2     1     0    Reset Value
//sfr CMOD  = 0xD9;	CIDL   -     -     -   CPS2   CPS1  CPS0  ECF   0xxx,0000	//PCA 工作模式寄存器。
#define PCA_IDLE_OFF()		CMOD |=  (1<<7)				//IDLE状态PCA停止计数。
#define PCA_IDLE_ON()		CMOD &= ~(1<<7)				//IDLE状态PCA继续计数。
#define PCA_CLK_12T()		CMOD &= ~0x0E				//PCA计数脉冲选择外部晶振/12。	fosc/12
#define PCA_CLK_2T()		CMOD = (CMOD & ~0x0E) + 2	//PCA计数脉冲选择外部晶振/2。	fosc/2
#define PCA_CLK_T0()		CMOD = (CMOD & ~0x0E) + 4	//PCA计数脉冲选择Timer0中断,Timer0可通过AUXR寄存器设置成工作在12T或1T模式。
#define PCA_CLK_ECI()		CMOD = (CMOD & ~0x0E) + 6	//PCA计数脉冲选择从ECI/P3.4脚输入的外部时钟,最大 fosc/2。
#define PCA_CLK_1T()		CMOD = (CMOD & ~0x0E) + 8	//PCA计数脉冲选择外部晶振。		Fosc/1
#define PCA_CLK_4T()		CMOD = (CMOD & ~0x0E) + 10	//PCA计数脉冲选择外部晶振/4。	Fosc/4
#define PCA_CLK_6T()		CMOD = (CMOD & ~0x0E) + 12	//PCA计数脉冲选择外部晶振/6。	Fosc/6
#define PCA_CLK_8T()		CMOD = (CMOD & ~0x0E) + 14	//PCA计数脉冲选择外部晶振/8。	Fosc/8
#define PCA_INT_ENABLE()	CMOD |=  1					//PCA计数器溢出中断允许位,1---允许CF(CCON.7)产生中断。
#define PCA_INT_DISABLE()	CMOD &= ~1					//PCA计数器溢出中断禁止。//					    7      6       5        4       3       2       1      0    Reset Value
//sfr AUXR1 = 0xA2;	  S1_S1  S1_S0  CCP_S1   CCP_S0  SPI_S1   SPI_S0    -     DPS   0100,0000	//Auxiliary Register 1#define		PCA_USE_P12P11P10P37()	AUXR1 &= ~0x30		//将PCA/PWM切换到P12(ECI) P11(CCP0) P10(CCP1) P37(CCP2)(上电默认)。
#define		PCA_USE_P34P35P36P37()	AUXR1 = (AUXR1 & ~0x30) | 0x10	//将PCA/PWM切换到P34(ECI) P35(CCP0) P36(CCP1) P37(CCP2)。
#define		PCA_USE_P24P25P26P27()	AUXR1 = (AUXR1 & ~0x30) | 0x20	//将PCA/PWM切换到P24(ECI) P25(CCP0) P26(CCP1) P27(CCP2)。#define		DPS_SEL1()		AUXR1 |=  1		//1:选择DPTR1。
#define		DPS_SEL0()		AUXR1 &= ~1		//0:选择DPTR0(上电默认)。/*									7     6      5      4     3     2     1     0     Reset Value
//sfr CCAPM0 = 0xDA;	PWM 寄存器  -   ECOM0  CAPP0  CAPN0  MAT0  TOG0  PWM0  ECCF0   x000,0000	//PCA 模块0 
//sfr CCAPM1 = 0xDB;	PWM 寄存器  -   ECOM1  CAPP1  CAPN1  MAT1  TOG1  PWM1  ECCF1   x000,0000	//PCA 模块1
//sfr CCAPM2 = 0xDC;	PWM 寄存器  -   ECOM2  CAPP2  CAPN2  MAT2  TOG2  PWM2  ECCF2   x000,0000	//PCA 模块2
;ECOMn = 1:	允许比较功能。
;CAPPn = 1:	允许上升沿触发捕捉功能。
;CAPNn = 1:	允许下降沿触发捕捉功能。
;MATn  = 1:	当匹配情况发生时,允许CCON中的CCFn置位。
;TOGn  = 1:	当匹配情况发生时,CEXn将翻转。(CEX0/PCA0/PWM0/P3.7,CEX1/PCA1/PWM1/P3.5)
;PWMn  = 1:	将CEXn设置为PWM输出。
;ECCFn = 1:	允许CCON中的CCFn触发中断。
;ECOMn CAPPn CAPNn MATn TOGn PWMn ECCFn
;  0     0     0    0    0    0     0		00H	未启用任何功能。
;  x     1     0    0    0    0     x	 	20H	16位CEXn上升沿触发捕捉功能。
;  x     0     1    0    0    0     x	 	10H	16位CEXn下降沿触发捕捉功能。
;  x     1     1    0    0    0     x	 	30H	16位CEXn/PCAn边沿(上、下沿)触发捕捉功能。
;  1     0     0    1    0    0     x	 	48H	16位软件定时器。
;  1     0     0    1    1    0     x	 	4CH	16位高速脉冲输出。
;  1     0     0    0    0    1     0		42H	8位PWM。无中断
;  1     1     0    0    0    1     1		63H	8位PWM。低变高可产生中断
;  1     0     1    0    0    1     1		53H	8位PWM。高变低可产生中断
;  1     1     1    0    0    1     1		73H	8位PWM。低变高或高变低均可产生中断
;*******************************************************************
;*******************************************************************/
#define		PCA0_none()				CCAPM0 = 0
#define		PCA0_PWM(nbit)			CCAPM0 = 0x42,PCA_PWM0 = (PCA_PWM0 & 0x0c) | ((8-nbit)<<6)
#define		PCA0_PWM_rise_int(nbit) CCAPM0 = 0x63,PCA_PWM0 = (PCA_PWM0 & 0x0c) | ((8-nbit)<<6)
#define		PCA0_PWM_fall_int(nbit) CCAPM0 = 0x53,PCA_PWM0 = (PCA_PWM0 & 0x0c) | ((8-nbit)<<6)
#define		PCA0_PWM_edge_int(nbit) CCAPM0 = 0x73,PCA_PWM0 = (PCA_PWM0 & 0x0c) | ((8-nbit)<<6)
#define		PCA0_capture_rise()		CCAPM0 = (0x20 + 1)
#define		PCA0_capture_fall()		CCAPM0 = (0x10 + 1)
#define		PCA0_capture_edge()		CCAPM0 = (0x30 + 1)
#define		PCA0_16bit_Timer()		CCAPM0 = (0x48 + 1)
#define		PCA0_High_Pulse()		CCAPM0 = (0x4C + 1)#define		PCA1_none()				CCAPM1 = 0
#define		PCA1_PWM(nbit)			CCAPM1 = 0x42,PCA_PWM1 = (PCA_PWM1 & 0x0c) | ((8-nbit)<<6)
#define		PCA1_PWM_rise_int(nbit) CCAPM1 = 0x63,PCA_PWM1 = (PCA_PWM1 & 0x0c) | ((8-nbit)<<6)
#define		PCA1_PWM_fall_int(nbit) CCAPM1 = 0x53,PCA_PWM1 = (PCA_PWM1 & 0x0c) | ((8-nbit)<<6)
#define		PCA1_PWM_edge_int(nbit) CCAPM1 = 0x73,PCA_PWM1 = (PCA_PWM1 & 0x0c) | ((8-nbit)<<6)
#define		PCA1_capture_rise()		CCAPM1 = (0x20 + 1)
#define		PCA1_capture_fall()		CCAPM1 = (0x10 + 1)
#define		PCA1_capture_edge()		CCAPM1 = (0x30 + 1)
#define		PCA1_16bit_Timer()		CCAPM1 = (0x48 + 1)
#define		PCA1_High_Pulse()		CCAPM1 = (0x4C + 1)#define		PCA2_none()				CCAPM2 = 0
#define		PCA2_PWM(nbit)			CCAPM2 = 0x42,PCA_PWM2 = (PCA_PWM2 & 0x0c) | ((8-nbit)<<6)
#define		PCA2_PWM_rise_int(nbit) CCAPM2 = 0x63,PCA_PWM2 = (PCA_PWM2 & 0x0c) | ((8-nbit)<<6)
#define		PCA2_PWM_fall_int(nbit) CCAPM2 = 0x53,PCA_PWM2 = (PCA_PWM2 & 0x0c) | ((8-nbit)<<6)
#define		PCA2_PWM_edge_int(nbit) CCAPM2 = 0x73,PCA_PWM2 = (PCA_PWM2 & 0x0c) | ((8-nbit)<<6)
#define		PCA2_capture_rise()		CCAPM2 = (0x20 + 1)
#define		PCA2_capture_fall()		CCAPM2 = (0x10 + 1)
#define		PCA2_capture_edge()		CCAPM2 = (0x30 + 1)
#define		PCA2_16bit_Timer()		CCAPM2 = (0x48 + 1)
#define		PCA2_High_Pulse()		CCAPM2 = (0x4C + 1)/* Above is STC additional SFR or change *//**********************************************************/
typedef 	unsigned char	u8;
typedef 	unsigned int	u16;
typedef 	unsigned long	u32;/**********************************************************/
#define NOP1()  _nop_()
#define NOP2()  NOP1(),NOP1()
#define NOP3()  NOP2(),NOP1()
#define NOP4()  NOP3(),NOP1()
#define NOP5()  NOP4(),NOP1()
#define NOP6()  NOP5(),NOP1()
#define NOP7()  NOP6(),NOP1()
#define NOP8()  NOP7(),NOP1()
#define NOP9()  NOP8(),NOP1()
#define NOP10() NOP9(),NOP1()
#define NOP11() NOP10(),NOP1()
#define NOP12() NOP11(),NOP1()
#define NOP13() NOP12(),NOP1()
#define NOP14() NOP13(),NOP1()
#define NOP15() NOP14(),NOP1()
#define NOP16() NOP15(),NOP1()
#define NOP17() NOP16(),NOP1()
#define NOP18() NOP17(),NOP1()
#define NOP19() NOP18(),NOP1()
#define NOP20() NOP19(),NOP1()
#define NOP21() NOP20(),NOP1()
#define NOP22() NOP21(),NOP1()
#define NOP23() NOP22(),NOP1()
#define NOP24() NOP23(),NOP1()
#define NOP25() NOP24(),NOP1()
#define NOP26() NOP25(),NOP1()
#define NOP27() NOP26(),NOP1()
#define NOP28() NOP27(),NOP1()
#define NOP29() NOP28(),NOP1()
#define NOP30() NOP29(),NOP1()
#define NOP31() NOP30(),NOP1()
#define NOP32() NOP31(),NOP1()
#define NOP33() NOP32(),NOP1()
#define NOP34() NOP33(),NOP1()
#define NOP35() NOP34(),NOP1()
#define NOP36() NOP35(),NOP1()
#define NOP37() NOP36(),NOP1()
#define NOP38() NOP37(),NOP1()
#define NOP39() NOP38(),NOP1()
#define NOP40() NOP39(),NOP1()
#define NOP(N)  NOP##N()/**********************************************//****************************************************************///sfr INT_CLKO = 0x8F;	//附加的 SFR WAKE_CLKO (地址:0x8F)
/*7   6    5    4   3     2        1       0         Reset Value-  EX4  EX3  EX2  -   T2CLKO   T1CLKO  T0CLKO      0000,0000B
b6 -  EX4      : 外中断INT4允许
b5 -  EX3      : 外中断INT3允许
b4 -  EX2      : 外中断INT2允许
b2 - T1CLKO    : 允许 T2 溢出脉冲在P3.0脚输出,Fck1 = 1/2 T1 溢出率
b1 - T1CLKO    : 允许 T1 溢出脉冲在P3.4脚输出,Fck1 = 1/2 T1 溢出率
b0 - T0CLKO    : 允许 T0 溢出脉冲在P3.5脚输出,Fck0 = 1/2 T0 溢出率
*/#define		LVD_InterruptEnable()		ELVD = 1
#define		LVD_InterruptDisable()		ELVD = 0//sfr WKTCL = 0xAA;	//STC11F\10和STC15系列 唤醒定时器低字节
//sfr WKTCH = 0xAB;	//STC11F\10和STC15系列 唤醒定时器高字节
//	B7		B6	B5	B4	B3	B2	B1	B0		B7	B6	B5	B4	B3	B2	B1	B0
//	WKTEN				S11	S10	S9	S8		S7	S6	S5	S4	S3	S2	S1	S0	n * 560us
#define		WakeTimerDisable()		WKTCH &= 0x7f	//WKTEN = 0		禁止睡眠唤醒定时器
#define		WakeTimerSet(scale)		WKTCL = (scale) % 256,WKTCH = (scale) / 256 | 0x80	//WKTEN = 1	允许睡眠唤醒定时器//sfr CLK_DIV = 0x97; //Clock Divder 系统时钟分频  -     -      -       -     -  CLKS2 CLKS1 CLKS0 xxxx,x000
#define		SYSTEM_CLK_1T()		CLK_DIV &= ~0x07	//default
#define		SYSTEM_CLK_2T()		CLK_DIV = (CLK_DIV & ~0x07) | 1
#define		SYSTEM_CLK_4T()		CLK_DIV = (CLK_DIV & ~0x07) | 2
#define		SYSTEM_CLK_8T()		CLK_DIV = (CLK_DIV & ~0x07) | 3
#define		SYSTEM_CLK_16T()	CLK_DIV = (CLK_DIV & ~0x07) | 4
#define		SYSTEM_CLK_32T()	CLK_DIV = (CLK_DIV & ~0x07) | 5
#define		SYSTEM_CLK_64T()	CLK_DIV = (CLK_DIV & ~0x07) | 6
#define		SYSTEM_CLK_128T()	CLK_DIV =  CLK_DIV          | 7#define		MCLKO_P54_None()	CLK_DIV &= ~0xc0					//主时钟不输出
#define		MCLKO_P54_DIV1()	CLK_DIV  = (CLK_DIV & ~0xc0) | 0x40	//主时钟不分频输出
#define		MCLKO_P54_DIV2()	CLK_DIV  = (CLK_DIV & ~0xc0) | 0x80	//主时钟2分频输出
#define		MCLKO_P54_DIV4()	CLK_DIV  =  CLK_DIV | 0xc0			//主时钟4分频输出#define		MCLKO_P34_None()	CLK_DIV &= ~0xc0					//主时钟不输出
#define		MCLKO_P34_DIV1()	CLK_DIV  = (CLK_DIV & ~0xc0) | 0x40	//主时钟不分频输出
#define		MCLKO_P34_DIV2()	CLK_DIV  = (CLK_DIV & ~0xc0) | 0x80	//主时钟2分频输出
#define		MCLKO_P34_DIV4()	CLK_DIV  =  CLK_DIV | 0xc0			//主时钟4分频输出//sfr BUS_SPEED = 0xA1; //Stretch register      -   -  -  -   -   -  EXRTS1  EXRTSS0 xxxx,xx10
#define		BUS_SPEED_1T()	BUS_SPEED = 0
#define		BUS_SPEED_2T()	BUS_SPEED = 1
#define		BUS_SPEED_4T()	BUS_SPEED = 2
#define		BUS_SPEED_8T()	BUS_SPEED = 3/*   interrupt vector */
#define		INT0_VECTOR		0
#define		TIMER0_VECTOR	1
#define		INT1_VECTOR		2
#define		TIMER1_VECTOR	3
#define		UART1_VECTOR	4
#define		ADC_VECTOR		5
#define		LVD_VECTOR		6
#define		PCA_VECTOR		7
#define		UART2_VECTOR	8
#define		SPI_VECTOR		9
#define		INT2_VECTOR		10
#define		INT3_VECTOR		11
#define		TIMER2_VECTOR	12
#define		INT4_VECTOR		16
#define		UART3_VECTOR	17
#define		UART4_VECTOR	18
#define		TIMER3_VECTOR	19
#define		TIMER4_VECTOR	20#define	TRUE	1
#define	FALSE	0//=============================================================//========================================#define	PolityLow			0	//低优先级中断
#define	PolityHigh			1	//高优先级中断//========================================#define		MCLKO_None	0
#define		MCLKO_DIV1	1
#define		MCLKO_DIV2	2
#define		MCLKO_DIV4	3#define		ENABLE		1
#define		DISABLE		0#define		STC15F_L2K08S2	8
#define		STC15F_L2K16S2	16
#define		STC15F_L2K24S2	24
#define		STC15F_L2K32S2	32
#define		STC15F_L2K40S2	40
#define		STC15F_L2K48S2	48
#define		STC15F_L2K56S2	56
#define		STC15F_L2K60S2	60
#define		IAP15F_L2K61S2	61#endif

USART.h

去掉了发送缓冲区, 使用阻塞发送.
注释掉了一些没用的临时代码(STC官方库中确实有一些临时代码没有注释掉)
添加了一个临时全局buffer, 供格式化字符串用.


#ifndef __USART_H
#define __USART_H	 #include	"config.h"// #define	COM_TX1_Lenth	128
#define	COM_RX1_Lenth	128
#define	COM_TX2_Lenth	128
#define	COM_RX2_Lenth	128#define	USART1	1
#define	USART2	2#define	UART_ShiftRight	0		//同步移位输出
#define	UART_8bit_BRTx	(1<<6)	//8位数据,可变波特率
#define	UART_9bit		(2<<6)	//9位数据,固定波特率
#define	UART_9bit_BRTx	(3<<6)	//9位数据,可变波特率#define	UART1_SW_P30_P31	0
#define	UART1_SW_P36_P37	(1<<6)
#define	UART1_SW_P16_P17	(2<<6)	//必须使用内部时钟
#define	UART2_SW_P10_P11	0
#define	UART2_SW_P46_P47	1#define	TimeOutSet1		5
#define	TimeOutSet2		5#define	BRT_Timer1	1
#define	BRT_Timer2	2typedef struct
{ u8	id;				//串口号// u8	TX_read;		//发送读指针// u8	TX_write;		//发送写指针// TI/TI2在上电后为0// 发送一个字节后, 不一定会先进中断, 此时TI标志还是0// 所以需要发送时, 置一个忙标志.// 防止发送一个字节后, 没进串口发送中断了, 就发送下一个字节, 导致发送内容丢失// 在初始化时, 置B_TX_busy = 0.// 在发送时, 等待((0 == TI) && (0 == B_TX_busy))才发送// 在发送前, 置B_TX_busy = 1// 发送后, 就可以离开了.// 在中断中, 清 TI = 0, 清 B_TX_busy = 0// 这样, 就可以保证每一个字节都发送成功.u8	B_TX_busy;		//忙标志u8 	RX_Cnt;			//接收字节计数u8	RX_TimeOut;		//接收超时u8	B_RX_OK;		//接收块完成
} COMx_Define; typedef struct
{ u8	UART_Mode;			//模式,         UART_ShiftRight,UART_8bit_BRTx,UART_9bit,UART_9bit_BRTxu8	UART_BRT_Use;		//使用波特率,   BRT_Timer1,BRT_Timer2u32	UART_BaudRate;		//波特率,       ENABLE,DISABLEu8	Morecommunicate;	//多机通讯允许, ENABLE,DISABLEu8	UART_RxEnable;		//允许接收,   ENABLE,DISABLEu8	BaudRateDouble;		//波特率加倍, ENABLE,DISABLEu8	UART_Interrupt;		//中断控制,   ENABLE,DISABLEu8	UART_Polity;		//优先级,     PolityLow,PolityHighu8	UART_P_SW;			//切换端口,   UART1_SW_P30_P31,UART1_SW_P36_P37,UART1_SW_P16_P17(必须使用内部时钟)u8	UART_RXD_TXD_Short;	//内部短路RXD与TXD, 做中继, ENABLE,DISABLE} COMx_InitDefine; extern	COMx_Define	COM1,COM2;
extern	u8 	xdata RX1_Buffer[COM_RX1_Lenth];	//接收缓冲
extern	u8 	xdata RX2_Buffer[COM_RX2_Lenth];	//接收缓冲extern u8 xdata g_tmp_buf[128];u8	USART_Configuration(u8 UARTx, COMx_InitDefine *COMx);
void TX1_write2buff(u8 dat);	//写入发送缓冲,指针+1
void TX2_write2buff(u8 dat);	//写入发送缓冲,指针+1
void PrintString1(u8 *puts);
void PrintString2(u8 *puts);//void COMx_write2buff(COMx_Define *COMx, u8 dat);	//写入发送缓冲,指针+1
//void PrintString(COMx_Define *COMx, u8 *puts);#endif

USART.C

主要是改了串口阻塞发送的操作(如何判断串口数据没发送完)
发送一个字符后, 即使是直接发送, 也不能保证再发送下一个字符时, 上一个字符就发送完了.
TI标志只能由串口发送中断程序来修改, 不能在串口中断之外修改.
在串口中断之外, 只能读串口发送字符完成的标志做判断.


#include "USART.h"COMx_Define	COM1,COM2;
// 不要发送缓冲, 直接发送完毕才离开
u8 	xdata RX1_Buffer[COM_RX1_Lenth];	//接收缓冲
u8 	xdata RX2_Buffer[COM_RX2_Lenth];	//接收缓冲u8 xdata g_tmp_buf[128];u8 USART_Configuration(u8 UARTx, COMx_InitDefine *COMx)
{u8	i;u32	j;if(UARTx == USART1){COM1.id = 1;COM1.B_TX_busy  = 0;COM1.RX_Cnt     = 0;COM1.RX_TimeOut = 0;COM1.B_RX_OK    = 0;for(i=0; iUART_Mode > UART_9bit_BRTx)	return 2;	//模式错误if(COMx->UART_Polity == PolityHigh)		PS = 1;	//高优先级中断else									PS = 0;	//低优先级中断SCON = (SCON & 0x3f) | COMx->UART_Mode;if((COMx->UART_Mode == UART_9bit_BRTx) ||(COMx->UART_Mode == UART_8bit_BRTx))	//可变波特率{j = (MAIN_Fosc / 4) / COMx->UART_BaudRate;	//按1T计算if(j >= 65536UL)	return 2;	//错误j = 65536UL - j;if(COMx->UART_BRT_Use == BRT_Timer1){TR1 = 0;AUXR &= ~0x01;		//S1 BRT Use Timer1;TMOD &= ~(1<<6);	//Timer1 set As TimerTMOD &= ~0x30;		//Timer1_16bitAutoReload;AUXR |=  (1<<6);	//Timer1 set as 1T modeTH1 = (u8)(j>>8);TL1 = (u8)j;ET1 = 0;	//禁止中断TMOD &= ~0x40;	//定时INT_CLKO &= ~0x02;	//不输出时钟TR1  = 1;}else if(COMx->UART_BRT_Use == BRT_Timer2){AUXR &= ~(1<<4);	//Timer stopAUXR |= 0x01;		//S1 BRT Use Timer2;AUXR &= ~(1<<3);	//Timer2 set As TimerAUXR |=  (1<<2);	//Timer2 set as 1T modeTH2 = (u8)(j>>8);TL2 = (u8)j;IE2  &= ~(1<<2);	//禁止中断AUXR &= ~(1<<3);	//定时AUXR |=  (1<<4);	//Timer run enable}else return 2;	//错误}else if(COMx->UART_Mode == UART_ShiftRight){if(COMx->BaudRateDouble == ENABLE)	AUXR |=  (1<<5);	//固定波特率SysClk/2else								AUXR &= ~(1<<5);	//固定波特率SysClk/12}else if(COMx->UART_Mode == UART_9bit)	//固定波特率SysClk*2^SMOD/64{if(COMx->BaudRateDouble == ENABLE)	PCON |=  (1<<7);	//固定波特率SysClk/32else								PCON &= ~(1<<7);	//固定波特率SysClk/64}if(COMx->UART_Interrupt == ENABLE)	ES = 1;	//允许中断else								ES = 0;	//禁止中断if(COMx->UART_RxEnable == ENABLE)	REN = 1;	//允许接收else								REN = 0;	//禁止接收P_SW1 = (P_SW1 & 0x3f) | (COMx->UART_P_SW & 0xc0);	//切换IOif(COMx->UART_RXD_TXD_Short == ENABLE)	PCON2 |=  (1<<4);	//内部短路RXD与TXD, 做中继, ENABLE,DISABLEelse									PCON2 &= ~(1<<4);return	0;}if(UARTx == USART2){COM2.id = 2;COM2.B_TX_busy  = 0;COM2.RX_Cnt     = 0;COM2.RX_TimeOut = 0;COM2.B_RX_OK    = 0;for(i=0; iUART_Mode == UART_9bit_BRTx) ||(COMx->UART_Mode == UART_8bit_BRTx))	//可变波特率{if(COMx->UART_Polity == PolityHigh)		IP2 |=  1;	//高优先级中断else									IP2 &= ~1;	//低优先级中断if(COMx->UART_Mode == UART_9bit_BRTx)	S2CON |=  (1<<7);	//9bitelse									S2CON &= ~(1<<7);	//8bitj = (MAIN_Fosc / 4) / COMx->UART_BaudRate;	//按1T计算if(j >= 65536UL)	return 2;	//错误j = 65536UL - j;AUXR &= ~(1<<4);	//Timer stopAUXR &= ~(1<<3);	//Timer2 set As TimerAUXR |=  (1<<2);	//Timer2 set as 1T modeTH2 = (u8)(j>>8);TL2 = (u8)j;IE2  &= ~(1<<2);	//禁止中断AUXR |=  (1<<4);	//Timer run enable}else	return 2;	//模式错误if(COMx->UART_Interrupt == ENABLE)	IE2   |=  1;		//允许中断else								IE2   &= ~1;		//禁止中断if(COMx->UART_RxEnable == ENABLE)	S2CON |=  (1<<4);	//允许接收else								S2CON &= ~(1<<4);	//禁止接收P_SW2 = (P_SW2 & ~1) | (COMx->UART_P_SW & 0x01);	//切换IO}return 0;
}/*************** 装载串口发送缓冲 *******************************/void TX1_write2buff(u8 dat)
{COM1.B_TX_busy = 1; // 设置忙标记SBUF = dat; // 立刻发送do {} while ((0 != TI) || (0 != COM1.B_TX_busy)); // 等待发送完成
}void TX2_write2buff(u8 dat)
{COM2.B_TX_busy = 1; // 设置忙标记S2BUF = dat; // 立刻发送do {} while ((0 != TI2) || (0 != COM2.B_TX_busy)); // 等待发送完成
}void PrintString1(u8 *puts)
{for (; *puts != 0;	puts++) {TX1_write2buff(*puts); 	//遇到停止符0结束}
}void PrintString2(u8 *puts)
{for (; *puts != 0;	puts++)  TX2_write2buff(*puts); 	//遇到停止符0结束
}/********************* UART1中断函数************************/
void UART1_int (void) interrupt UART1_VECTOR
{if(RI){RI = 0;if(COM1.B_RX_OK == 0){if(COM1.RX_Cnt >= COM_RX1_Lenth)	COM1.RX_Cnt = 0;RX1_Buffer[COM1.RX_Cnt++] = SBUF;COM1.RX_TimeOut = TimeOutSet1;}}if(TI){// 发送标志, 只由串口中断来清除.TI = 0;COM1.B_TX_busy = 0;}
}/********************* UART2中断函数************************/
void UART2_int (void) interrupt UART2_VECTOR
{if(RI2){CLR_RI2();if(COM2.B_RX_OK == 0){if(COM2.RX_Cnt >= COM_RX2_Lenth)	COM2.RX_Cnt = 0;RX2_Buffer[COM2.RX_Cnt++] = S2BUF;COM2.RX_TimeOut = TimeOutSet2;}}if(TI2){// 发送标志, 只由串口中断来清除.CLR_TI2();COM2.B_TX_busy = 0;}
}

总结

第三方的库, 如果不是很复杂(觉得自己有能力维护, 工作量又不大), 那就自己搞, 对细节的理解更深刻.

END

相关内容

热门资讯

银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...
【NI Multisim 14...   目录 序言 一、工具栏 🍊1.“标准”工具栏 🍊 2.视图工具...
AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
Android|无法访问或保存... 这个问题可能是由于权限设置不正确导致的。您需要在应用程序清单文件中添加以下代码来请求适当的权限:此外...
月入8000+的steam搬砖... 大家好,我是阿阳 今天要给大家介绍的是 steam 游戏搬砖项目,目前...
​ToDesk 远程工具安装及... 目录 前言 ToDesk 优势 ToDesk 下载安装 ToDesk 功能展示 文件传输 设备链接 ...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
AWS管理控制台菜单和权限 要在AWS管理控制台中创建菜单和权限,您可以使用AWS Identity and Access Ma...