这两个程序(一个是 C 语言,另一个是 PIC 汇编语言)有什么区别?

问题描述 投票:0回答:1

我已经编写/复制/修改了一个用 C 编写的 I2C 客户端,它可以工作。当我将其翻译为汇编语言时,它失败了。我哪里错了?

主/从设计非常简单。主站向从站发送一个整数值。从机闪烁 LED 以显示接收到的值,然后递增该值并将其发送回主机。 当我运行 C 语言从属版本时,它按预期工作。当我运行汇编版本时,不会驱动中断,并且我观察到从属设备上没有任何活动(没有 LED 闪烁)。 我将发布 C 代码和相应的汇编代码,看看是否有人可以看到为什么汇编版本不起作用

这是C代码

/* 
 * File:   slave.c
 * Author: mike
 *
 * Created on 18 March 2024, 2:32 PM
 */

#include <stdio.h>
#include <stdlib.h>

/*

                                     PIC16F1503
                              +----------:_:----------+
                    +5V <>  1 : VDD               VSS : 14 <> GND
            RED LED o/p <>  2 : RA5               RA0 : 13 <> 
                        <>  3 : RA4               RA1 : 12 <> 
                        <>  4 : RA3/MCLR          RA2 : 11 <>      
                        <>  5 : RC5               RC0 : 10 <> SCL (input)
                        <>  6 : RC4               RC1 : 9  <> SDA (input) 
                        <>  7 : RC3               RC2 : 8  <> RED LED o/p
                              +-----------------------+
                                       DIP-14
 
 */
// PIC16F1503 Configuration Bit Settings

// CONFIG1
#pragma config FOSC = INTOSC    // Oscillator Selection Bits (INTOSC oscillator: I/O function on CLKIN pin)
#pragma config WDTE = OFF       // Watchdog Timer Enable (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable (PWRT disabled)
#pragma config MCLRE = ON       // MCLR Pin Function Select (MCLR/VPP pin function is MCLR)
#pragma config CP = OFF         // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config BOREN = ON       // Brown-out Reset Enable (Brown-out Reset enabled)
#pragma config CLKOUTEN = OFF   // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)

// CONFIG2
#pragma config WRT = OFF        // Flash Memory Self-Write Protection (Write protection off)
#pragma config STVREN = ON      // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset)
#pragma config BORV = LO        // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
#pragma config LPBOR = OFF      // Low-Power Brown Out Reset (Low-Power BOR is disabled)
#pragma config LVP = ON         // Low-Voltage Programming Enable (Low-voltage programming enabled)

// Set Clock Freq. & Delays
#define _XTAL_FREQ  16000000      // oscillator frequency for _delay()

#include <xc.h>

#define slaveAddress 0x60
// Set Clock Freq. & Delays
#define _XTAL_FREQ  16000000      // oscillator frequency for _delay()

#define testBit(var, bit)   (var & (1 << bit))
#define clearBit(var, bit)  (var ^= (1 << bit))
#define setBit(var, bit)    (var |= (1 << bit))

uint8_t temp, flagWord;
#define dataReceived 0

void __interrupt() ISR(void)
{
    if (PIR1bits.SSP1IF || PIR2bits.BCL1IF) {
        //Check for SSPIF
        if(PIR1bits.SSP1IF) {
            if (SSP1STATbits.P) { // Stop bit: 1 = stop detected
                //Stop Condition
                // do nothing
                ;
            }
            else if(SSP1STATbits.R_nW) { // R/W bit: 1 = read, 0 = write
                //Host wants to read (client transmit)
                // increment value in temp and send to master
                temp+=1;        // increment temp and return to master
                SSP1BUF = temp;
            }   
            else {  
                // Host wants to write (client receive)
                if(SSP1STATbits.D_nA) { // Data/Address: 1 = data, 0 = address
                    //Last byte was data
                    temp = SSP1BUF;
                    setBit(flagWord, dataReceived);
                }
                else {
                    //Last byte was an address
                    //Clear the Buffer Full (BF) flag
                    temp = SSP1BUF;
                }
            }
        }
        if(PIR2bits.BCL1IF) {
            //Clear the Buffer Full (BF) flag
            temp = SSP1BUF;

            // Clear BCLIF
            PIR2bits.BCL1IF = 0;
        }
    
        //Release Clock Stretch
        SSP1CON1bits.CKP = 1;

        //Clear SSP1IF
        PIR1bits.SSP1IF = 0;
    }
}

void flashLEDMultiple(uint8_t count) {
    for (int i=0; i<count; i++) {
        // turn LED on
        LATA5 = 1;
        __delay_ms(200);
        LATA5 = 0;
        if (i+1<count) {
            __delay_ms(200);
        }
    }
}

void main(void) {
    
    OSCCON = 0B01111000;        // set oscillator to 16MHz
    
    //Init the I2C Pins on the Device
    // RA0 = SCL, RA1 = SDA
    // RC0 = SCL, RC1 = SDA
    
    //Disable analog mode
    ANSELA = 0;     // all PORTA pins digital
    ANSELC = 0;     // all PORTC pins digital
    
    TRISCbits.TRISC0 = 0b1;
    TRISCbits.TRISC1 = 0b1;
    
    TRISAbits.TRISA5 = 0;   // output for LED
    LATAbits.LATA5 = 0;     // LED off
    
    //Initialize the I2C Driver
    //Reset Registers
    SSP1CON1 = 0x00;
    SSP1CON2 = 0x00;
    SSP1CON3 = 0x00;
    SSP1STAT = 0x00;
         
    SSP1STATbits.SMP = 1;   //Disable slew control for Standard mode
    SSP1CON1bits.SSPM = 0b0110; //Set MSSP Operating Mode (7-bit Client)
    SSP1CON2bits.SEN = 1;   //Enable clock stretching
    SSP1CON3bits.SBCDE = 1; //Enable bus collision interrupts
    SSP1ADD = (unsigned char)(slaveAddress << 1);   //Load slave address
    PIR2bits.BCL1IF = 0;    //Clear Bus Collision interrupt flag
    PIR1bits.SSP1IF = 0;    //Clear the SSP interrupt flag
    PIE2bits.BCL1IE = 1;    //Enable BCLIF
    PIE1bits.SSP1IE = 1;    //Enable SSPIF
    SSP1CON1bits.SSPEN = 1; //Enable the module
    INTCONbits.PEIE = 1;    // Enable peripheral interrupts
    INTCONbits.GIE = 1;     // Enable global interrupts                                                         
    
    while (1)
    {
        if (testBit(flagWord,dataReceived)) {
            clearBit(flagWord,dataReceived);
            flashLEDMultiple(temp); // flash the received count value
        }
    }
    
    return;
}

这是“相同的?”汇编代码(不起作用)

; Slave: Sample code to demonstrate use of the MSSP module to drive 
;    slave device via I2C
; Author:   Mike Brady
; Company:  Java Point Pty Ltd
;
;   Pin summary
;   1   VDD +3.3V
;   8   RC2 Red LED
;      14   VSS Ground
;    
;  Assembled with pic-as (v2.32) under MPLAB X IDE (v6.15) 4 Mar 2024
;
; Add this line in the project properties box, pic-as Global Options -> Additional options: 
;   -Wa,-a -Wl,-pPOR_Vec=0h,-pISR_Vec=4h
;
;
;                                     PIC16F1503
;                              +----------:_:----------+
;                    +5V <>  1 : VDD               VSS : 14 <> GND
;            RED LED o/p <>  2 : RA5               RA0 : 13 <> 
;                    <>  3 : RA4               RA1 : 12 <> 
;                        <>  4 : RA3/MCLR          RA2 : 11 <>      
;                        <>  5 : RC5               RC0 : 10 <> SCL (input)
;                        <>  6 : RC4               RC1 : 9  <> SDA (input) 
;                        <>  7 : RC3               RC2 : 8  <> 
;                              +-----------------------+
;                                       DIP-14
;    
    
PAGEWIDTH   132
RADIX       DEC

#include <xc.inc>

; See respective data sheet for additional information on configuration word.
config FOSC = INTOSC    ; Oscillator Selection bits (HS oscillator)
config WDTE = OFF       ; Watchdog Timer (WDT disabled)
config PWRTE = OFF      ; Power-up Timer Enable bit (Power-up Timer is disabled)
config CP = OFF         ; Code Protection bit (Code protection disabled)
config MCLRE = ON
config BOREN = ON
config CLKOUTEN = OFF
config WRT = OFF
config STVREN = OFF
config LVP = OFF
config LPBOR = OFF
config BORV = LO
    
; vars used by TimerLib library
global      d1,d2,d3
extrn       delay5us

    
#define FOSC        16000   ; Oscillator Clock in kHz    
                
#define dataReceived 0
    
//I2C Test Properties
#define SLAVE_ADDRESS 0x60  ; unique address for this slave
    
;**********************************************************************
; Power-On-Reset entry point
;**********************************************************************
PSECT POR_Vec,global,class=CODE,delta=2
    global  resetVec
resetVec:
    goto    main

;objects in Common RAM - address 70h
psect udata_shr,global,class=COMMON,space=1,delta=1,noexec
    d1:         DS  1
    d2:         DS  1
    d3:         DS  1
    flagWord:       DS  1
    bufferValue:    DS  1
    flashCounter:   DS  1
    
;**********************************************************************
; Interrupt vector and handler
;**********************************************************************
PSECT ISR_Vec,global,class=CODE,delta=2
    global  ISR_Vec
    
ISR_Vec:
    banksel PIR1
    btfsc   PIR1, PIR1_SSP1IF_POSN
    goto    SSP_or_BCL_set
    btfss   PIR2, PIR2_BCL1IF_POSN
    retfie
    
SSP_or_BCL_set:
    btfss   PIR1, PIR1_SSP1IF_POSN
    goto    checkBusCollision
    banksel SSP1STAT
    btfss   SSP1STAT, SSP1STAT_R_nW_POSN
    goto    masterSending
    incf    bufferValue,f
    movf    bufferValue,w
    movwf   SSP1BUF
    goto    checkBusCollision
    
masterSending:
    btfss   SSP1STAT, SSP1STAT_D_nA_POSN
    goto    processAddress
    movf    SSP1BUF     ; read value from buffer
    movwf   bufferValue ; store received value
    bsf     flagWord, dataReceived
    goto    checkBusCollision
    
processAddress:
    movf    SSP1BUF     ; clear the BF flag
    
checkBusCollision:
    banksel PIR2
    btfss   PIR2, PIR2_BCL1IF_POSN
    goto    clockRelease
    banksel SSP1BUF
    movf    SSP1BUF,w   ; clear the BF flag
    banksel PIR2
    bcf     PIR2, PIR2_BCL1IF_POSN
    
clockRelease:
    banksel SSP1CON1
    bsf     SSP1CON1, SSP1CON1_CKP_POSN
    banksel PIR1
    bcf PIR1, PIR1_SSP1IF_POSN
    retfie
    
END_ISR_Vec:

;PSECT MainCode,global,class=CODE,delta=2
psect code,global,class=CODE,delta=2
    
initialisation:    ; setup peripherals, start timer
    call    setupOscillator
    call    setupIOPins
    call    I2C_init
    return
   
setupOscillator:
    ; initialise internal oscillator to 16MHz
    banksel OSCCON
    movlw   01111000B       ; Int. osc. 16 MHz
    movwf   OSCCON 
    btfss   HFIOFR      ; Int. osc. running?
    goto    $-1         ; No, loop back
    btfss   HFIOFS      ; Osc. stable?
    goto    $-1         ; No, loop back.
    return

setupIOPins:  ; RA0 - SCL, RA1 = SDA
    banksel ANSELA
    clrf    ANSELA      ; all PORTA pins digital
    clrf    ANSELC      ; all PORTC pins digital

    ; set all PORTA pins as output
    banksel TRISA   
    clrf    TRISA       ; set all PORTA as output
    ; set RC0 and RC1 as input, the rest as output
    clrf    TRISC
    bsf     TRISC, TRISC_TRISC0_POSN
    bsf     TRISC, TRISC_TRISC1_POSN
    
    ; turn off LED
    bcf     LATA, LATA_LATA5_POSN
    return
  
I2C_init:
    ;Configure MSSP module for Slave Mode
    banksel SSP1CON1
    clrf    SSP1CON1
    clrf    SSP1CON2
    clrf    SSP1CON3
    clrf    SSP1STAT
    
    bsf     SSP1STAT, SSP1STAT_SMP_POSN ; Disable slew control for Standard mode
    movlw   00000110B   ; Set MSSP Operating Mode (7-bit Client)
    iorwf   SSP1CON1,f  
    bsf     SSP1CON2, SSP1CON2_SEN_POSN ; Enable clock stretching
    bsf     SSP1CON3, SSP1CON3_SBCDE_POSN ; Enable bus collision interrupts
    movlw   SLAVE_ADDRESS<<1
    movwf   SSP1ADD     ; Load slave address
    banksel PIR2
    bcf     PIR2, PIR2_BCL1IF_POSN  ; Clear Bus Collision interrupt flag
    bcf     PIR1, PIR1_SSP1IF_POSN  ; Clear the SSP interrupt flag
    banksel PIE2
    bsf     PIE2, PIE2_BCL1IE_POSN  ; Enable bus collision interrupt
    bsf     PIE1, PIE1_SSP1IE_POSN  ; Enable MSSP interrupt
    bsf     INTCON, INTCON_PEIE_POSN
    bsf     INTCON, INTCON_GIE_POSN
    
    return

;**********************************************************************
; main program
;**********************************************************************
main:
    call    initialisation
    
loop:
    btfss   flagWord, dataReceived
    goto    loop
    bcf     flagWord, dataReceived
    movf    bufferValue, w
    call    flashLEDMultiple
    goto    loop
    
flashLEDMultiple:
    movwf   flashCounter
    call    flashLED
    call    delay200ms
    decfsz  flashCounter, f
    goto    flashLEDMultiple
    return
    
flashLED:
    banksel LATA
    bsf     LATA, LATA_LATA5_POSN
    call    delay200ms
    bcf     LATA, LATA_LATA5_POSN
    return
    
delay200ms:
    movlw   0x6D
    movwf   d1
    movlw   0xBF
    movwf   d2
    movlw   0x02
    movwf   d3
delay200ms_0:
    decfsz  d1, f
    goto    $+2
    decfsz  d2, f
    goto    $+2
    decfsz  d3, f
    goto    delay200ms_0
    return

显然这两个程序在功能上并不等同,但我很难看出它们有何不同。 希望有眼力的人能指出他们的不同之处。

@Lundin 中断未被驱动/调用。我没有可用的调试器,但我使用 LED 闪烁来显示代码的哪些部分正在执行。我只是没有在已发布的代码中显示它们。

@Erik Eidt 反汇编代码看起来非常标准。除了存储体选择之外,它还直接进入 SSP1IF 和 BCL1IF 的标志测试。我附上了屏幕片段Disassembled ISR

@Frankie_C 的目的是总是在退出时当SSP1IF中断发生时设置CKP标志,我相信代码会这样做。 ISR 地址在链接器中使用指令 -pISR_Vec=4h 设置。

c assembly pic
1个回答
0
投票

汇编版本有几个错误。

  1. 最重要的是,SSPEN 没有被设置。
  2. 从机地址初始化无效。表达方式 项目
© www.soinside.com 2019 - 2024. All rights reserved.