第5集 C语言基础 摘要 1) C语言USB-CDC串口之printf函数的实现 2) 数的进制:二进制、10进制、十六进制 3) 数据的基本类型 4) C语言常用运算符 详细步骤: 1. C语言USB-CDC串口printf函数的实现: 1.1. 打开USB库(stc_sub_)中的PRINTF_HID宏定义(去掉//) 1.1.1. 先打开一个程序代码,实际操作一下,打开上一个工程,复制代码,打开stc32_stc8_usb.h头文件,其中的// #define PRINTF_HID ,删除反斜杠“//”恢复USB HID定义功能。 1.1.2. 有同学反应:上一节课的USB不停电下载不成功。原因有2个: 1.1.2.1. Keill_v5 软件options for Target’Target 1’工具栏选项中的配置: 1.1.2.2. 其中Memory model选择:Xsmdll:near vars,for const,ptr-4 1.1.2.3. St_usb_cdc_32.lib 库文件未添加进来。 1.2. 理解PRINTF函数原型的定义: #define printf printf_hid //所有printf_hid出现的地都可以用printf替代 Int printf_hid(const char *fmt,…); 1.2.1. 参数fmt--是格式控制字符串,包含了两种类型的对象:普通字符和转换说明。 1.2.1.1. 普通字符:在输出时,普通字符原样不动地复制到标准输出 1.2.1.2. 转换说明: 1.2.1.2.1. 类型:根据不同fmt字符串,函数可能需要一系列附加参数,每个参数包含了一个要被插入的值,替换了fmt参数中指定的每个%标签。关于附加参数,既可以是变量,也可以是常量。 1.2.1.2.2. 位置:printf()函数的普通字符和转换说明,放在“”双引号内,附加参数放在双引号外,每个附加参数之间用逗号隔开。 1.2.1.2.3. 数量:printf()的附加参数与转换说明符是一一对应关系,如果有n个转换说明符,printf()的参数就应该有n+1个。如果参数个数少于对应的转换说明符,printf()可能会输出内存中的任意值。(参考转义字符与格式字符) 1.2.1.2.4. 上述过程可通过程序下载测试验证。 1.3. 格式字符: 1.3.1. %d……十进制整型 1.3.2. %ld……十进制长整型 1.3.3. %f……单精度浮点型 1.3.4. %lf……双精度浮点型 1.3.5. %o……八进制整型 1.3.6. %x……十六进制整型 1.3.7. %u……十进制无符号整型 1.3.8. %i……十进制整型(与%d无异) 1.3.9. %c……输出单个字符 1.3.10. %s……输出字符串 1.3.11. %e……输出指数形式 1.3.12. %g……自适应输出(数据够大或够小,则以指数形式输出,否则以小数形式输出) 1.3.13. %p……输出地址 1.3.14. Print f(“今天是%d年%d月%d日\r\n”,24,11,16),打印输出:今天是24年11月16日 1.3.15. 1.4. 转义字符: 1.4.1. \?……书写连续多个问号时使用,防止被解析成三字字词 1.4.2. \’……用于表示字符常量;即表示1个单引号(‘),通常用于单引号内嵌套单引号时使用。 1.4.3. \”……用于表示一个双引号(”),通常用于双引号内嵌套双引号时使用;如”他说:”你好””,在计算机中,要修改为:”他说:\”你好\””,防止计算机误读为:”他说:”+你好+””,导致最后2个双引号为错误语法。 1.4.4. \\……用于表示一个反斜杠(\);由于(\)本身已被定义为转义字符,但如果实际需要反斜杠表示路径时,需要用双反斜杠表示,以防止被解释为一个转义序列符;如要表示:C:\Users\Documents,在C语言程序中不能直接写,而应写成C:\\Users\\Documents。 1.4.5. \a……警告、蜂鸣 1.4.6. \b……退格符 1.4.7. \f……换页符 1.4.8. \n……换行符(单片机程序中用“\r\n”表示) 1.4.9. \r……回车 1.4.10. \t……水平制表符(TAB键,8个空格) 1.4.11. \v……垂直制表 1.4.12. \ddd……ddd表示1~3个八进制数 1.4.13. \xdd……dd表示2个十六进制数 1.5. 标志 1.5.1. n.m……n几行整,m几行小数;示例:%2.3f 1.5.2. -……左对齐;示例:%-d 1.5.3. 空格……输出值正时空格,负时负号;%#d 1.5.4. #……输出带前导数据:八进制o~~~,十六进制x~~~,其中~表示数字,如%#d;示例:%#d 1.6. ASCII码:定义字符串与十六进制数据之间的转换关系,在单片机程序中经常使用,帮助我们加深理解C语言程序及单片机软件硬件之间的逻辑关系;在ISP软件中程序发送、接收缓冲区,设置显示方式,有文本显示(即字符串),也可同时设置HEX显示(十六进数据),我们对照ASCII码,可以计算它们之间转换关系,或者在程序式计算器中直接换算,在调试某些数值变量时就特别有用。 1.6.1. 2. 数的进制:二进制、10进制、十六进制 2.1. 二进制:逢2进1,所以只有1和0两个数,英文写法:Binary,简写Bin 2.2. 八进制:逢8进1,所以只有0、1、2、3、4、5、6、7,8、9,共10位数,英文写法:Octal,简写Oct 2.3. 十进制:逢10进1,所以有0、1、2、3、4、5、6、7,8、9,共10位数,英文写法:Decimal,简写Dec 2.4. 十六进制:逢16进1,所以有0、1、2、3、4、5、6、7、8、9、A、B、C、D、E、F ,共16位数,英文写法:Hexadecimal,简写Hex。在内存地址中表示:0x 2.5. 数的进制之间转换,可以统一转换为十进制作为中间换算,也可直接计算器(程序式)中直接换算。 3. 数据的基本类型: 3.1. AI8051U-32BIT是基于32位数据变量,但有些浮点式运算,占至64位变量:double(64位),那么在C语言程序中,我们必须添加如下申明: 3.1.1. #pragma float64 3.2. Data Type: 3.2.1. bit: 1Bits 0Bytes 0 or 1 value range; 3.2.2. Signed char: 8Bits 1Bytes -128~+127 value range; 3.2.3. unSigned char: 8Bits 1Bytes 0~+255 value range; 3.2.4. Enum: 16Bits 2Bytes -32768~+32767 value range; 3.2.5. Signed short int: 16Bits 2Bytes -32768~+32767 value range; 3.2.6. unSigned short int: 16Bits 2Bytes 0~+65535 value range; 3.2.7. Signed int: 16Bits 2Bytes -32768~+32767 value range; 3.2.8. unSigned int: 16Bits 2Bytes 0~+65535 value range; 3.2.9. Signed long int: 32Bits 4Bytes 2147483648~+2147483647 value range; 3.2.10. unSigned long int: 32Bits 4Bytes 0~+4294967295 value range; 3.2.11. Float: 32Bits 4Bytes ±1.17549435e-38~±3.4028235e+38 value range; 3.2.12. Double: 64Bits 8Bytes ±2.2250738585072014e-308~±1.7976931348623158e+308 value range; 3.2.13. Idata*,data*,pdata*(pointers): 8Bits 1Bytes 0~0xFF value range; 3.2.14. near*,xdata*,code*(pointers): 16Bits 2Bytes 0~0xFFFF value range; 3.2.15. far*,huge*(pointers): 32Bits 4Bytes 0~0xFFFFFF value range; 3.2.16. Sbit: 1Bits 0Bytes 0 or 1 value range; 3.2.17. Sfr: 8Bits 1Bytes 0~+255 value range; 3.2.18. Sfr16: 16Bits 2Bytes 0~+65535 value range; 3.2.19. Note:These data types are not provided in ANSI C.They are unique to the C251 compiler.(这些数据类型不提供ANSI C码,它们是独特的C251编译器) 3.2.20. Without using the FLOAT64 compiler Directive,the sixze and range of double is the same as float.(如不使用FLOAT64编译指令,double与float数据大小与范围相同) 3.3. 所以,为了使用64位变量double,在程序开头,必须加上:#pragma float64申明。 3.4. 变量类型,可以在程序中重新定义,示例:unsigned char可以用u8替代;那么,我们可以这样定义: 3.5. #define u8 unsigned char: 其中u8……替代变量,unsigned char……被替代变量。 在程序中的表示: #define u8 unsigned char //8位无符号变量(0~+255),u8替代 unsigned char #define u16 unsigned char //16位无符号变量(0-+65535) U8 X=20; U8 Y=10; …… Void main(void) { …… While(DeviceState!=DEVSTATE_CONFIGURED); While(1) { If(bUsbOutReady) { Printf(“X/Y=%u\r\n”,(u16)(X/Y)); Printf(“X%%Y=%u\r\n”,(u16)(X%Y)); //%%前1个%是转义符,后1个%才是取余运算符; Usb_OUT_done(); } } } 备注:上述程序通过编译ISP下载、缓冲区显示,验证结果正确。 3.6. 实际上在单片机里,可能还需要加上地址修饰符,如:xdata,edata等,后面详细讲解。 4. C语言常用运算符(0为假,非0为真): 4.1. 算术运算符: 4.1.1. +(加)、-(减)、*(乘)、/(除)、%(取模运算,整除后余数)、++(自加运算,整数数值加1)、 --(自减运算,整数数值减1) 4.1.2. 假设X=20,Y=10:则X+Y=30,X-Y=10,X*Y=200,X/Y=2,X%Y=0,X++=21,X--=19 4.2. 关系运算符(假设X=20,Y=10): 4.2.1. ==: 检查2个操作数是否相等,相等则为真,(X==Y)为假。 4.2.2. !=:检查2个操作数是否相等,不相等则为真,(X!=Y)为真。 4.2.3. > : 检查左操作数是否大于右操作数,是则为真,(X> Y)为真。 4.2.4. > : 检查左操作数是否大于右操作数,是则为真,(X> Y)为真。 4.2.5. < : 检查左操作数是否小于右操作数,是则为真,(X< Y)为假。 4.2.6. > =:检查左操作数是否大于等于右操作数,是则为真,(X> =Y)为真。 4.2.7. < =:检查左操作数是否小于等于右操作数,是则为真,(X<= Y)为假。 4.2.8. 注意:0为假,非0为真,用if等判断语句,需要用到真和假的概念,真则执行,否则(假)不执行。 4.2.9. 上述运算符,在判断语句经常使用如:if(X>Y){条件为真}else{条件为假}。 4.3. 逻辑运算符{假设A=5(0000 0101),B=10(0000 1010),用二进制计算}: 4.3.1. &&:逻辑与。皆真为真,有假为假。(A&&B)为真。 4.3.2. ||:逻辑异或运算符。皆假为假,有真为真;(A||B)为真。 4.3.3. !:逻辑非运符。用来逆转操作的状态,使真为假,假为真。(!A)为假。 4.4. 赋值运算符: 4.4.1. =:赋值运算符运算符;右侧操作数赋值给左侧操作数;C=A+B,将A+B的值赋值给C。 4.4.2. +=:加且赋值运算符;左边操作数加右边操作数的结果赋值给左边操作数;C+=A即C=C+A。 4.4.3. -=:减且赋值运算符;左边操作数减右边操作数的结果赋值给左边操作数;C-=A即C=C-A。 4.4.4. *=:乘且赋值运算符;左边操作数乘右边操作数的结果赋值给左边操作数;C*=A即C=C*A。 4.4.5. /=:除且赋值运算符;左边操作数除右边操作数的结果赋值给左边操作数;C/=A即C=C/A。 4.4.6. %=:求模且赋值运算符;左边操作数除右边操作数的余数赋值给左边操作数;C%=A即C=C%A(C/A的余数)。 4.4.7. <<=:左移且赋值运算符; C<<=2 即 C=C<<2 4.4.8. >>=右移且赋值运算符; C>>=2 即 C=C>>2 4.4.9. &=:按位与且赋值运算符; C&=2 即 C=C&2 4.4.10. ^=:按位异或且赋值运算符; C^=2 即 C=C^2 4.4.11. |=:按位或且赋值运算符; C|=2 即 C=C|2 4.5. 位运算符: 4.5.1. &:与运算符;同一为一,其它为零; 4.5.2. |:或运算符;有一为一,皆零为零; 4.5.3. ^:异或运算符;相同为零,不同为一; 4.5.4. ~:取反运算符;零变一,一变零; 4.5.5. <<:二进制左移运算符;左操作数值向左(高位)移动,右操作数指定位数(低位补零) 4.5.6. >>:二进制右移运算符;左操作数值向右(低位)移动,右操作数指定位数(高位补零) 4.6. 其它运算符: 4.6.1. Condition ? x:y 如果condition 为真,则值为X,否则值为Y; 4.6.2. .点和->(箭头):成员运算符,用于引用类、结构体、共用体成员;结 4.6.3. &: 取地址运算符;返回变量的存储地址; 4.6.4. *:指针运算符,指向一个变量;如*a,指向变量a; 4.6.5. ,:逗号运算符;会顺序执行一系列运算;整个逗号表达式的值是以逗号分隔的列表中的最后一个表达式的值。 |