技术热线: 4007-888-234

从一个简单的AD转换程序(C语言)想开去

更新时间: 2019-03-23
阅读量:2888

十年专注单片机方案开发的方案公司英锐恩,分享从一个简单的A/D转换程序(C语言)想开去。英锐恩现提供服务产品涉及主控芯片:8位单片机、16位单片机、32位单片机及各类运算放大器等。

从一个简单的A/D转换程序(C语言)想开去

从一个简单的A/D转换程序(C语言)想开去以下是一个A/D转换程序,所用芯片是16F72 unsigned char adc(void) //使用RA0,VREF=RA3 { unsigned char i; ADCON1=0x05; ADCON0=0x40; ADON=1; i=0x20; while(i--) //等待一段时间(A/D采样) ADGO=1; //启动A/D转换 while(ADGO) //等待A/D转换完成 return(ADRES); //取结果返回 } 第一个问题:网上经常有人问“会C语言后还要学汇编吗?” 第二个问题:这个程序是否还有问题?要回答第一个问题,先看一下编译后的程序,特别是while(i--)这一句 14: unsigned char adc(void) //使用RA0,VREF=RA3 15: { unsigned char i; 0004ED 3005 MOVLW 0x5 16: ADCON1=0x05; 0004EE 1683 BSF 0x3, 0x5 0004EF 1303 BCF 0x3, 0x6 0004F0 09F MOVWF 0x1f 17: ADCON0=0x40; 0004F1 3040 MOVLW 0x40 0004F2 1283 BCF 0x3, 0x5 0004F3 09F MOVWF 0x1f 18: ADON=1; 0004F4 141F BSF 0x1f, 0 19: i=0x20; 0004F5 3020 MOVLW 0x20 0004F6 0A1 MOVWF 0x21 20: while(i--) //等待一段时间(A/D采样) 0004F7 2CFB GOTO 0x4fb 0004FB 1283 BCF 0x3, 0x5 0004FC 1303 BCF 0x3, 0x6 0004FD 3A1 DECF 0x21, F 0004FE F21 INCFSZ 0x21, W 0004FF 2D01 GOTO 0x501 000500 2D02 GOTO 0x502 000501 2CF8 GOTO 0x4f8 21: ADGO=1; //启动A/D转换 0004F8 1283 BCF 0x3, 0x5 0004F9 1303 BCF 0x3, 0x6 0004FA 151F BSF 0x1f, 0x2 22: while(ADGO) //等待A/D转换完成 000502 2D07 GOTO 0x507 000507 1283 BCF 0x3, 0x5 000508 1303 BCF 0x3, 0x6 000509 191F BTFSC 0x1f, 0x2 00050A 2D0C GOTO 0x50c 00050B 2D0D GOTO 0x50d 00050C 2D03 GOTO 0x503 23: return(ADRES); //取结果返回 000503 1283 BCF 0x3, 0x5 000504 1303 BCF 0x3, 0x6 000505 81E MOVF 0x1e, W 000506 2D0D GOTO 0x50d 24: } 00050D 1303 BCF 0x3, 0x6

把while(i--)改成while(--i)后再编译 20: while(--i) //等待一段时间(A/D采样) 0004F8 2CFC GOTO 0x4fc 0004FC 1283 BCF 0x3, 0x5 0004FD 1303 BCF 0x3, 0x6 0004FE BA1 DECFSZ 0x21, F 0004FF 2D01 GOTO 0x501 000500 2D02 GOTO 0x502 000501 2CF9 GOTO 0x4f9 21: ADGO=1; //启动A/D转换 0004F9 1283 BCF 0x3, 0x5 0004FA 1303 BCF 0x3, 0x6 0004FB 151F BSF 0x1f, 0x2 22: while(ADGO) //等待A/D转换完成 000502 2D07 GOTO 0x507 编译后程序更简单更易理解,从这个例子可看出熟悉汇编可以编出更高效的C

第二个问题,其实本程序是有问题的,最大问题出在while(--i)和while(ADGO) 应改成如下写法: unsigned char adc(void) //使用RA0,VREF=RA3 { unsigned char i; ADCON1=0x05; ADCON0=0x40; ADON=1; i=0x20; while(--i){} //等待一段时间(A/D采样) ADGO=1; //启动A/D转换 while(ADGO){} //等待A/D转换完成 return(ADRES); //取结果返回 }

20: while(--i){} //等待一段时间(A/D采样) 0004F9 2CFA GOTO 0x4fa 0004FA 1283 BCF 0x3, 0x5 0004FB BA1 DECFSZ 0x21, F 0004FC 2CFE GOTO 0x4fe 0004FD 2CFF GOTO 0x4ff 0004FE 2CFA GOTO 0x4fa 21: ADGO=1; //启动A/D转换 0004FF 1283 BCF 0x3, 0x5 000500 1303 BCF 0x3, 0x6 000501 151F BSF 0x1f, 0x2 22: while(ADGO){} //等待A/D转换完成 000502 2D03 GOTO 0x503 000503 1283 BCF 0x3, 0x5 000504 

1303 BCF 0x3, 0x6 000505 191F BTFSC 0x1f, 0x2 000506 2D08 GOTO 0x508 000507 2D09 GOTO 0x509 000508 2D03 GOTO 0x503 23: return(ADRES); //取结果返回 000509 1283 BCF 0x3, 0x5 00050A 1303 BCF 0x3, 0x6 00050B 81E MOVF 0x1e, W 00050C 2D0D GOTO 0x50d 24: } 00050D 1303 BCF 0x3, 0x6

第三个问题,为什么在判断语句后连着有三个GOTO?而我们用汇编编写时只一个GOTO就够了。?

给你看看我编译的结果

1: #include 2: 3: unsigned char adc(void) //使用RA0,VREF=RA3 4: { unsigned char i; 0007F0 3005 MOVLW 0x5 5: ADCON1=0x05; 0007F1 1683 BSF 0x3, 0x5 0007F2 1303 BCF 0x3, 0x6 0007F3 09F MOVWF 0x1f 6: ADCON0=0x40; 0007F4 3040 MOVLW 0x40 0007F5 1283 BCF 0x3, 0x5 0007F6 09F MOVWF 0x1f 7: ADON=1; 0007F7 141F BSF 0x1f, 0 8: i=0x20; 0007F8 3020 MOVLW 0x20 0007F9 0A0 MOVWF 0x20 9: while(--i); //等待一段时间(A/D采样) 0007FA BA0 DECFSZ 0x20, F 0007FB 2FFA GOTO 0x7fa 10: ADGO=1; //启动A/D转换 0007FC 151F BSF 0x1f, 0x2 11: while(ADGO); //等待A/D转换完成 0007FC 191F BTFSC 0x1f, 0x2 0007FD 2FFC GOTO 0x7fc 12: return(ADRES); //取结果返回 0007FE 81E MOVF 0x1e, W 13: } 0007FF 008 RETURN

你把优化关掉了,打开的步骤: Project -> Build Options -> Project 在Build Options窗口里点PICC Compiler 将Enable assembler optimization选中,然后再编译。不要小看PICC哦!另,你程序里的明显错误,while(i--)后面要加分号,while(ADGO)后面也要加分号。

优化的结果居然与我写的汇编一样,一条都不多,一条都不少。为什么while(--i)后面未加分号时编译,链接都通过?PICC应该提示我呀, 1:while(--i)后面未加分号时,编译没错误,但程序的逻辑是错的。 2:改成while(--i){}时,程序的逻辑是正确的 3:while(--i);表示什么?我遇到这种情况总写成 while(--i){} 4:再次感谢

{} ;都可以的

没有操作的时候全部是空操作,所以编译后就两条。很多说c效率低的都是因为结构差,对自己写的源码优化差导致容量变大。可以这么说,不熟练的使用者用两种方式变出来的代码差不多大小,c可能要略小一些,也就是对数据结构和MCU特点一无所知。中等熟练的,也就是对数据结构比较清楚,比较熟悉MCU特点,代码会很接近。只有真正的汇编高手,也就是说用了多年汇编,非常熟悉MCU本身,对算法和数据结构很清楚才可能做到小!不信大家可以比一比,当然硬要抠那种三五个字节的没办法比。 10%以上误差很难。

又,不要认为c编译器弱智, i=j/256;在c中一样会编译成直接被赋成高字节或者右移8位!类似的例子太多了,编译了看看就知道。