我给你来个 C 程序试试
|
shumivan 发表于 2021-9-8 16:03 要提高编程能力,汇编是必须要学会的, 可以平时不用, 但必须要会, debug的时候,有问题,看一眼编译出来的汇编,立马就能明白是什么原因造成的,不会的话,会走很多弯路, 然后,C语言里不好控制的时序问题,进到汇编跟砍瓜切菜一样。 程序主体都用C, 有些地方(尤其是涉及底层操作的地方)用点汇编,我觉得还是比较有必要的。 |
| 怎么还在用汇编,我已经全忘完了,只会C了 |
Y_G_G 发表于 2021-9-6 22:29 谢谢您的回复,受教了。最近在写E2PROM复制器的程序,就是将两个24C32,将其中一个里面的数据,通过单片机复制到另一个里面去,可总是写不好,思路一直混乱。请大神给指点个好的思路,按您的思路,我在重新写程序。 |
| 代码不全吧 |
|
学PIC的本来就少,你还是用汇编的,而且一个汉字注释都没有,你觉得别人能看明白? 这是我以前写的24C02的验证程序,已经在开发板上实际验证过的,你对比一下吧 我已经好久没有用PIC汇编了,指令都快忘记完了 #include <p16f877a.inc> ;包含了PIC16F877A的寄存器声称文件 __CONFIG _FOSC_HS & _WDTE_OFF & _PWRTE_OFF & _BOREN_ON & _LVP_OFF & _CPD_OFF & _WRT_OFF & _CP_OFF;配置设置生成的代码 CBLOCK 020H ;定义连续变量 COUNT ;计数用的 DEL1 ;用在延时子程序中 DEL2 ;用在延时子程序中 DEL3 ; DISP_ADDR ;显示地址用寄存器 DISP_DATA ;显示数据用寄存器 LED_1 ;七段码的个位 LED_10 ;七段码的十位 LED_100 ;七段码的百位 DIV_DATA ;除法用寄存器 DATA_BUF ;数据写入和读出用的缓冲器 SESHI ;测试用寄存器 ENDC ;结束定义 #define S1 PORTB,0 ;按置S1 #define S2 PORTB,1 ;按置S2 #define S3 PORTB,2 ;按置S3 #define COM0 PORTD,0 ; #define COM1 PORTD,1 ; #define COM2 PORTD,2 ; #define COM3 PORTD,3 ;定义几个显示的RA端口 #define CY STATUS,0 ;C为标志位,减法有借位=0,无借位=1 #define SCL PORTD,4 ;时钟信号线 #define SDA PORTD,7 ;数据信号线 #define SDA_C TRISD,7 ;数据方向控制寄存器 ORG 00H ; NOP ;这条指令是仿真要有的 GOTO MAIN ;跳过中断子程序 ORG 020H ; MAIN BSF STATUS,RP0 ;RP0=1,RP1=0,指令选择BANK1 BCF STATUS,RP1 ; ;=============================================================================== ;以下是针对BANK1的操作========================================================== MOVLW 0FFH ; MOVWF TRISB ;PORTB 作为输入 BCF OPTION_REG,7 ;启用RB的上拉电阻 BCF INTCON,3 ; MOVLW 00H ; MOVWF TRISC ;PORTC 作为输出-数据 MOVWF TRISD ;PORTD 作为输出-位选 CLRF TRISE ;RD工作于正常的IO模式 ;以下是针对BANK0的操作========================================================== BCF STATUS,RP0 ;选择BANK0 CLRF PORTC ; CLRF PORTD ;=============================================================================== MOVLW D'123' ;默认数据是000 MOVWF DISP_DATA MOVLW D'8' ;默认地址是0 MOVWF DISP_ADDR ;=============================================================================== LOOP BTFSS S1 ;按键1是1就跳过下一条指令 CALL S1_DISP ;调用S1处理程序 BTFSS S2 ;S2没有按下就跳过下一条指令 CALL S2_DISP ;按下就调用S2处理子程序 BTFSS S3 ;S3没有按下就跳过下一条指令 CALL S3_DISP ;按下就中用S3处理子程序 CALL DISPLAY ;显示 GOTO LOOP ;主程序在这循环 ;=============================================================================== READ_DATA;读出一个字节---------------------------------------------------------- BCF SCL ; BSF SDA ;SDA1 BSF SCL ; 1 BCF SDA ;SDA1>>0,起始信号 BCF SCL ; ;----------------------------------------------------------------------- MOVLW 0A0H ;0A0H为写命令,完整的输入8个位的地址 CALL WRITE_BYTE ;写入"写"模式指令 MOVFW DISP_ADDR ;写入地址 CALL WRITE_BYTE ; ;----------------------------------------------------------------------- BCF SCL ; BSF SDA ;SDA1 BSF SCL ; BCF SDA ;SDA1>>0,起始信号 BCF SCL ; ;----------------------------------------------------------------------- MOVLW 0A1H ;0A1H为读命令,完整的输入8个位的地址 CALL WRITE_BYTE ;写入"写"模式指令 CALL READ_BYTE ;读出一个字节 MOVWF DISP_DATA ;----------------------------------------------------------------------- BCF SCL ; BCF SDA ;SDA0 BSF SCL ; BSF SDA ;SDA0>>1,停止信号 BCF SCL ; BCF SDA RETURN ;=============================================================================== WRITE_DATA;写入一个字节--------------------------------------------------------- BCF SCL ; BSF SDA ;SDA1 BSF SCL ; 1 BCF SDA ;SDA1>>0,起始信号 BCF SCL ; ;----------------------------------------------------------------------- MOVLW 0A0H ;0A0H为写命令,完整的输入8个位的地址 CALL WRITE_BYTE ;写入"写"模式指令 MOVFW DISP_ADDR ;写入地址 CALL WRITE_BYTE ; MOVFW DISP_DATA CALL WRITE_BYTE ;----------------------------------------------------------------------- BCF SCL ; BCF SDA ;SDA0 BSF SCL ; BSF SDA ;SDA0>>1,停止信号 BCF SCL ; BCF SDA RETURN ;=============================================================================== READ_BYTE;读一个字节处理程序*************************************************** BSF STATUS,RP0 ;选择BANK1 BSF SDA_C ;SDA作为输入 BCF STATUS,RP0 ;选择BANK0 MOVLW D'8' MOVWF COUNT ;要读出的字节是8 BCF SCL ;时钟0 R_B_LOOP BCF CY ; BSF SCL ;时钟上升沿 BTFSC SDA ;是0就跳过下一条指令 BSF CY ;是1,置位缓冲器的0位 RLF DATA_BUF,F ;左移一次,从最高位开始读出 BCF SCL ;时钟下降 DECFSZ COUNT,F ;检测是否完成了8个字节 GOTO R_B_LOOP ; MOVFW DATA_BUF ;读取到的数据保存到W BSF STATUS,RP0 ;选择BANK1 BCF SDA_C ;SDA作为输出 BSF SDA ; BSF SCL ; BCF SCL ; BCF SDA ; BCF STATUS,RP0 ;选择BANK0 RETURN ;=============================================================================== WRITE_BYTE;写入一个字节********************************************************* BSF STATUS,RP0 ;选择BANK1 BCF SDA_C ;SDA作为输出 BCF STATUS,RP0 ;选择BANK0 MOVWF DATA_BUF ; MOVLW D'8' ; MOVWF COUNT ; BCF SCL ;时钟0 W_B_LOOP BCF SDA ;清除输出线 BTFSC DATA_BUF,7 ;最高位如果是0就跳过下一条指令 BSF SDA ;最高位是1,置位D_I CALL DELAY_5MS ;延时5mS BSF SCL ;时钟上升 CALL DELAY_5MS BCF SCL ;时钟下降 CALL DELAY_5MS RLF DATA_BUF,F ;左移一次, DECFSZ COUNT,F ;检测是否传送完成8个字节 GOTO W_B_LOOP ;没有,跳去循环 ;应答--------------------------------------------------------------- BSF SDA BSF STATUS,RP0 ;选择BANK1 BSF SDA_C ;SDA作为输入 BCF STATUS,RP0 ;选择BANK0 BSF SCL ; CALL DELAY_5MS ;延时5mS BTFSC SDA ;SDA为0就跳过下一条指令 GOTO $-1 ;SDA为1,跳动循环 BSF STATUS,RP0 ;选择BANK1 BCF SDA_C ;SDA作为输出 BCF STATUS,RP0 ;选择BANK0 BCF SCL ; BCF SDA RETURN ;=============================================================================== ;按一下,数据显示就加1 S1_DISP;S1处理程序************************************************************** BTFSS S1 GOTO $-1 INCF DISP_DATA,F ;数据加1,保存到F CALL WRITE_DATA ;写入数据 CALL DELAY_5MS CALL READ_DATA ;再读出数据 RETURN ;=============================================================================== S2_DISP;S2处理程序************************************************************** BTFSS S2 GOTO $-1 DECF DISP_DATA,F ;数据减1,保存到F CALL WRITE_DATA ;写入数据 CALL DELAY_5MS CALL READ_DATA ;再读出数据 RETURN ;=============================================================================== ;按一下,地址就加1,最大显示到9 S3_DISP ;S2处理程序************************************************************* BTFSS S3 GOTO $-1 INCF DISP_ADDR,F ;地址的值加1 MOVLW D'10' ;10传送到W SUBWF DISP_ADDR,W ;地址-W,结果保存到W BTFSC CY ;c进位为1,地址的值就是大于等于9了 CLRF DISP_ADDR ;地址清零 CALL READ_DATA ;再读出数据 RETURN ;=============================================================================== ;显示程序*********************************************************************** DISPLAY BCF STATUS,RP0 ;选择BANK0 CLRF LED_1 CLRF LED_10 CLRF LED_100 ;除法部分----------------------------------------------------------------------- MOVFW DISP_DATA ;送显示数据到W DIV_100 MOVWF DIV_DATA ;W的值保存到寄存器 MOVLW D'100' ;W等于100 SUBWF DIV_DATA,W ;数据减去100,结果保存在W BTFSS STATUS,C ;C是1就跳过下一条指令,C=1,F就是大,还可以再减法 GOTO DIV_10 ;C=0,F已经小于100,跳转到减10 INCF LED_100,F ;F大,百位加1 GOTO DIV_100 ;再去减一次 ;------------------------------------------------------------------------------- DIV_10 MOVLW D'10' ;W等于10 SUBWF DIV_DATA,W ;DIV_DATRA-10= BTFSS STATUS,C ;C=1,DIV_DATA就比W大 GOTO DIV_1 ; INCF LED_10,F ; MOVWF DIV_DATA ;W数据保存到寄存器 GOTO DIV_10 ; ;------------------------------------------------------------------------------- DIV_1 MOVFW DIV_DATA MOVWF LED_1 ;显示部分----------------------------------------------------------------------- MOVFW LED_1 ;数据送到W CALL TAB_LED ;查表 MOVWF PORTC ;W送到端口 BCF COM0 ;低电平,亮灯 CALL DELAY_5MS ;延时5mS BSF COM0 ;高电平,关灯 ;----------------------------------------------------------------------- MOVFW LED_10 ; CALL TAB_LED ;查表 MOVWF PORTC ; BCF COM1 ; CALL DELAY_5MS ; BSF COM1 ; ;----------------------------------------------------------------------- MOVFW LED_100 ; CALL TAB_LED ;查表 MOVWF PORTC ; BCF COM2 ; CALL DELAY_5MS ; BSF COM2 ; ;----------------------------------------------------------------------- MOVFW DISP_ADDR ;显示地址 CALL TAB_LED ;查表 MOVWF PORTC ; BCF COM3 ; CALL DELAY_5MS ; BSF COM3 ; ;----------------------------------------------------------------------- RETURN ; ;=============================================================================== ;5mS延时程序******************************************************************** DELAY_5MS MOVLW 3H MOVWF DEL3 MOVLW D'2' ; MOVWF DEL1 ; LOOP_5MS1 MOVLW D'1' ; MOVWF DEL2 ; LOOP_5MS2 DECFSZ DEL2,F ; GOTO LOOP_5MS2 ;100x2=200uS DECFSZ DEL1,F ; GOTO LOOP_5MS1 ; DECFSZ DEL3 GOTO LOOP_5MS1 ; RETURN ; ;=============================================================================== ;BCD码的表********************************************************************** TAB_LED ADDWF PCL,F ;把W的内容叠加到PCL程序计数器上 RETLW 0FCH ;0 RETLW 060H ;1 RETLW 0DAH ;2 RETLW 0F2H ;3 RETLW 066H ;4 RETLW 0B6H ;5 RETLW 0BEH ;6 RETLW 0E0H ;7 RETLW 0FEH ;8 RETLW 0F6H ;9 END |