打印

单片机混合编程的问题

[复制链接]
1653|21
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
黑小子mxx|  楼主 | 2015-5-15 16:51 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
沙发
黑小子mxx|  楼主 | 2015-5-15 17:01 | 只看该作者
难道没有人遇到这样的情况么?

使用特权

评论回复
板凳
黑小子mxx|  楼主 | 2015-5-15 17:27 | 只看该作者
自己再顶一下!

使用特权

评论回复
地板
ayb_ice| | 2015-5-15 20:24 | 只看该作者
int flag;   mov a,flag   mov b,flag+1

使用特权

评论回复
5
黑小子mxx|  楼主 | 2015-5-16 11:01 | 只看该作者
ayb_ice 发表于 2015-5-15 20:24
int flag;   mov a,flag   mov b,flag+1

多谢大神,发现你真的好热心,好多帖子都是你解答的!根据你的建议,最后是这样解决的:
比如我要对这个int变量执行加1操作
C51:
         unsigned int value;
A51:
         EXTRN   DATA   (value);
                     .
                     .
                     .

         MOV B,value+1;
         MOV A,B
         ADD A,#1;
         MOV B,A

         MOV A,value;
         ADDC A,#0;

         MOV value,A;
         MOV value+1,B
不知道我理解的对不对,或者还有没有更简单的办法!

使用特权

评论回复
6
ayb_ice| | 2015-5-16 11:06 | 只看该作者
本帖最后由 ayb_ice 于 2015-5-16 11:09 编辑
黑小子mxx 发表于 2015-5-16 11:01
多谢大神,发现你真的好热心,好多帖子都是你解答的!根据你的建议,最后是这样解决的:
比如我要对这个i ...

差不多吧,不过不够简练
        mov                a, value+1
        add                a,#1
        mov                value+1,a

        mov                a, value+0
        addc          a,#0
        mov                value+0,a

使用特权

评论回复
7
ayb_ice| | 2015-5-16 11:10 | 只看该作者
        inc                value+1
        mov                a, value+1
        jnz                $+2+2
        inc                value+0

使用特权

评论回复
8
黑小子mxx|  楼主 | 2015-5-16 12:42 | 只看该作者
ayb_ice 发表于 2015-5-16 11:10
inc                value+1
        mov                a, value+1
        jnz                $+2+2

这确实够简练,可是我不太明白这里是怎么实现进位的,汇编学的不咋的,还望前辈指点!
另外,由于我这几句话是放在定时器中断里面的,value作为系统时钟节拍计数器。上面三种方式(包括我自己的)都能实现对C51中int型进行加1,但是我发现这样以后会不停的中断,只进了一次主函数就再也进不去了。我把上面几句话改回原来的INC value(不能实现对int型加1)就又没问题了。不知道为什么?

使用特权

评论回复
9
黑小子mxx|  楼主 | 2015-5-16 12:43 | 只看该作者
ayb_ice 发表于 2015-5-16 11:10
inc                value+1
        mov                a, value+1
        jnz                $+2+2

T0ISRcode        SEGMENT CODE                ;Segment for interrupt function
                RSEG    T0ISRcode        ;Switch to this code segment
                USING   1               ;Register bank for interrupt routine
; Tick the system counter[Tick5ms] in every 5ms
TF0_ISR:        CLR        TR0                ;Pause timer0
                PUSH    PSW
                PUSH        ACC
                ;MOV     PSW,#08H        ;Select register bank 1
        
                ;Reload timer0 offset for 5ms overflow rate. 0DC00H for
                ;1.8432MHz RC clock and 2800H for external 11.0592MHz.
                MOV        TL0,#(00H+18+2)        ;Compensate for 10 ISR + 8 INTR cycles
                MOV        TH0,#0DCH
                SETB        TR0                ;Restart timer0
               
        ;INC     Tick5ms+1
        ;MOV     A, Tick5ms+1
        ;JNZ     $+2+2
        ;INC     Tick5ms+0
               
                ;MOV       A,Tick5ms+1
        ;ADD       A,#1
        ;MOV       Tick5ms+1,A

        ;MOV       A,Tick5ms+0
        ;ADDC      A,#0
        ;MOV       Tick5ms+0,A
                INC        Tick5ms                ;System tick by 5ms

                                POP         ACC
                POP     PSW
                RETI

上面是中断处理函数

使用特权

评论回复
10
ayb_ice| | 2015-5-16 16:22 | 只看该作者
黑小子mxx 发表于 2015-5-16 12:42
这确实够简练,可是我不太明白这里是怎么实现进位的,汇编学的不咋的,还望前辈指点!
另外,由于我这几 ...

加一后等于0,就会有进位啊,比如一位十进位,加一后等于0,只可能是9+1,当然要进位了

使用特权

评论回复
11
ayb_ice| | 2015-5-16 16:28 | 只看该作者
黑小子mxx 发表于 2015-5-16 12:43
T0ISRcode        SEGMENT CODE                ;Segment for interrupt function
                RSEG   ...

这个中断程序没有发现什么问题,应该是主循环有问题,读写那个整型变量要关掉中断才能确保完全正确

使用特权

评论回复
12
黑小子mxx|  楼主 | 2015-5-17 16:49 | 只看该作者
ayb_ice 发表于 2015-5-16 16:22
加一后等于0,就会有进位啊,比如一位十进位,加一后等于0,只可能是9+1,当然要进位了 ...

额额额。明白了,脑子短路了!多谢!

使用特权

评论回复
13
黑小子mxx|  楼主 | 2015-5-17 16:51 | 只看该作者
本帖最后由 黑小子mxx 于 2015-5-17 16:53 编辑
ayb_ice 发表于 2015-5-16 16:28
这个中断程序没有发现什么问题,应该是主循环有问题,读写那个整型变量要关掉中断才能确保完全正确 ...

主循环里就一个时间处理函数,也没发现上面问题。最后没办法,还是只能用标志位:

T0ISRcode        SEGMENT CODE                ;Segment for interrupt function
                RSEG    T0ISRcode        ;Switch to this code segment
                USING   1               ;Register bank for interrupt routine
; Tick the system counter[Tick5ms] in every 5ms
TF0_ISR:        CLR        TR0                ;Pause timer0
                PUSH    PSW
                ;MOV     PSW,#08H        ;Select register bank 1
        
                ;Reload timer0 offset for 5ms overflow rate. 0DC00H for
                ;1.8432MHz RC clock and 2800H for external 11.0592MHz.
                MOV        TL0,#(00H+18)        ;Compensate for 10 ISR + 8 INTR cycles
                MOV        TH0,#0DCH
                SETB        TR0                ;Restart timer0
               
                INC        Tick5ms                ;System tick by 5ms               
                ; Produce a few reference time
                DJNZ        ref_100ms,ref_time_end;
                MOV        A,#20;
                MOV        ref_100ms,A
                SETB        flag_100ms;
                DJNZ        ref_1s,ref_time_end;
                MOV        A,#5;
                MOV        ref_500ms,A
                SETB        flag_500ms;
                DJNZ        ref_1s,ref_time_end
                MOV        A,#2;
                MOV        ref_1s,A;
                SETB        flag_1s;
                ref_time_end:
                                nop;

                POP     PSW
                RETI
但是这样的话就要浪费几个字节的内存,而且如果要改变时间间隔都要在中断函数里改,不知道有没有更好的办法!

使用特权

评论回复
14
ayb_ice| | 2015-5-18 07:53 | 只看该作者
黑小子mxx 发表于 2015-5-17 16:51
主循环里就一个时间处理函数,也没发现上面问题。最后没办法,还是只能用标志位:

T0ISRcode        SEGM ...

你主循环是怎么处理的,上代码

使用特权

评论回复
15
黑小子mxx|  楼主 | 2015-5-20 22:24 | 只看该作者
ayb_ice 发表于 2015-5-18 07:53
你主循环是怎么处理的,上代码

/**************************************************************/
/**/
/**/
/**************************************************************/
#include <at89lp52.h>  
#include <stdio.h>
#include "sensor.h"

#define uint unsigned int
#define uchar unsigned char

/*-------------------------------------------------------------*/
/****************Ports and variations dellarations**************/
/*-------------------------------------------------------------*/
sbit LED_PORT        = P3^6;
uchar ADS1115_BUF[9];
uchar Tick5ms_Num;
uchar channel_1, channel_2, channel_3;
unsigned long temperature, windspeed, humidity;       
float WS, RH, Pr, Te;
idata uchar Result1[17] = "     C      m/s";
idata uchar Result2[17] = "     %       hP";
bit k = 0;

extern bit        flag_100ms;
extern bit        flag_500ms;
extern bit        flag_1s;
extern bit RS485LSTN;
extern bit RS485TALK;
extern bit RS485DGrecv(void);
extern bit RS485DGsend(void);
extern bit RS485CheckDG(void);
extern uchar RS485BUFidx;
extern void RS485ParseDG(uchar *);

extern uint ADS1115_RD(uchar);
extern ADS1115_Scan(char *);
extern uchar ADS1115_chn;
extern        void MS5607_get_cal_params();
extern        void MS5607_calTP(void);
extern        int T100;        //Temperature[0.01C]
extern        long Pa;        //Pressure[Pa]

extern void System_Init(void);
extern void Wait_Ticks(void);
extern void Send2OLED(uchar *);

/*-------------------------------------------------------------*/
/***************************The End*****************************/
/*-------------------------------------------------------------*/

/*-------------------------------------------------------------*/
/****************Functions declarations of main.c***************/
/*-------------------------------------------------------------*/                                                                    
void FloatToStr(float, uchar *, uchar);
void Get_Data(void);
void Data_Prepare(void);
void RS484_Check(void);
void Delay_5ms(uint);
void Time_Event(void);
/*-------------------------------------------------------------*/
/***************************The End*****************************/
/*-------------------------------------------------------------*/  
            
/*-------------------------------------------------------------*/
/*************************Main function*************************/
/*-------------------------------------------------------------*/     
void main()   
{
                uchar j;
          System_Init();
                LED_PORT = 0;
                Delay_5ms(200);
                LED_PORT = 1;
                MS5607_get_cal_params();          
    while(1)   
    {
                               
                                Time_Event();

    }      
}

/*-------------------------------------------------------------*/
/******************************The End**************************/
/*-------------------------------------------------------------*/


/*-------------------------------------------------------------*/
/******************Functions Definitions of main.c**************/
/*-------------------------------------------------------------*/

//*************************************************************/
//*Function Name:FloatToStr(float num, uchar *str, uchar p)
//*Function     :change a float number into a string
//*Parameter    :float number,char string,start point
//*Return Value :None
//*************************************************************/
void FloatToStr(float num, uchar *str, uchar p)
{
        str[p+0] = (uint)num/10+0x30;
        str[p+1] = (uint)num%10+0x30;
        str[p+2] = '.';
        str[p+3] = (uint)(num*10)%10+0x30;
        str[p+4] = (uint)(num*100)%10+0x30;
}

//*************************************************************/
//*Function Name:Get_Data(void)
//*Function     :Get the Data from ADS1115
//*Parameter    :None
//*Return Value :None
//*************************************************************/
void Get_Data(void)                                    
{
                        if((ADS1115_RD(0X01)&0X8000))                        //Abort if OS=0[in conversion]
                        {
                                        ADS1115_Scan(ADS1115_BUF);
                                        if((ADS1115_chn & 0X03) == 0)        //The last conversion is channel 1
                                        {
                                                        channel_1++;
                                                        temperature += (ADS1115_BUF[0]*256 + ADS1115_BUF[1]);
                                        }
                                        if((ADS1115_chn & 0X03) == 1)        //The last conversion is channel 2
                                        {
                                                        channel_2++;
                                                        humidity += (ADS1115_BUF[2]*256 + ADS1115_BUF[3]);
                                        }
                                        if((ADS1115_chn & 0X03) == 2)        //The last conversion is channel 3
                                        {
                                                        channel_2++;
                                                        windspeed += (ADS1115_BUF[4]*256 + ADS1115_BUF[5]);
                                        }               
                                                       
                        }       
}

//*************************************************************/
//*Function Name:Data_Prepare(void)
//*Function     :Prepare the Data to be send
//*Parameter    :None
//*Return Value :None
//*************************************************************/
void Data_Prepare(void)
{
                        Te = Temperature(temperature/50.0);                               
                        RH = Humidity(humidity/50.0);
                        WS = Wind_Speed(windspeed/50.0);
                        Pr = Pa;       
               
                        temperature = 0;
                        humidity = 0;
                        windspeed = 0;                                                       
                        channel_1 = 0;
                        channel_2 = 0;
                        channel_3 = 0;
       
                        FloatToStr(Te, Result1, 0);
                        FloatToStr(WS, Result1, 7);
                        FloatToStr(RH, Result2, 0);
                        Result2[7] = (uint)Pr/1000+0x30;
                        Result2[8] = (uint)Pr%1000/100+0x30;
                        Result2[9] = (uint)Pr%100/10+0x30;
                        Result2[10] = (uint)Pr%10+0x30;
                        Result2[11] = '.';
                        Result2[12] = (uint)(Pr*10)%10+0x30;
                        Result1[15] = '\n';
                        Result2[15] = '\n';
}

//*************************************************************/
//*Function Name:RS484_Check(void)
//*Function     :Do the RS485 task
//*Parameter    :None
//*Return Value :None
//*************************************************************/
void RS484_Check(void)
{
                if(RS485LSTN)                                                                                                                                        //Client in LISTEN mode?
                {
                                if(!RS485DGrecv())                                                                                          //Receive one datagram
                                {
                                                LED_PORT = !LED_PORT;
                                                if(!RS485CheckDG())                                                                                //Check IDN and CKS...
                                                {
                                                                if(k == 0)                                                                                                //Send the first datagram(Temperature & Wind speed)
                                                                {
                                                                                k = 1;
                                                                                RS485ParseDG(Result1);                    //Processing the datagram and prepare the firt 16 bytes data to response
                                                                                RS485LSTN = 0;                                                                //Pause datagram listen
                                                                                RS485TALK = 1;                                                                //Ready to send the response datagram
                                                                }
                                                                else                                                                                                                        //Send the second datagram(Humidity & Presure)
                                                                {
                                                                                k = 0;
                                                                                RS485ParseDG(Result2);                    //Processing the datagram and prepare the firt 16 bytes data to response
                                                                                RS485LSTN = 0;                                                                //Pause datagram listen
                                                                                RS485TALK = 1;                                                                //Ready to send the response datagram                                                                                               
                                                                }

                                                }
                                                RS485BUFidx = 0;                                                                                        //Reset datagram buffer
                                }
                }
                if(RS485TALK)
                {
                                if(!RS485DGsend())
                                {
                                                LED_PORT = !LED_PORT;
                                }
                                RS485LSTN = 1;
                                RS485TALK = 0;
                }
}
//*************************************************************/
//*Function Name:void Time_Event(void)
//*Function     :execute task of different time interval
//*Parameter    :None
//*Return Value :None
//*************************************************************/
void Time_Event(void)
{
                //Set CPU into IDLE mode when no task to do
                //it will be woke up by interrupt every 5ms
                /***********Task in each 5ms interval************/
                PCON |= 0X01;                       
                Get_Data();
                RS484_Check();               
                /************************************************/
                if(flag_500ms == 1)
                {
                                /********Task in each 500ms interval*********/
                                flag_500ms = 0;
                                MS5607_calTP();
                                Data_Prepare();
//                                j++;
//                                if(j < 5)
//                                {
//                                                Send2OLED(Result1);
//                                }
//                                else
//                                {
//                                                Send2OLED(Result2);
//                                                if(j == 10)
//                                                        j = 0;
                                /********************************************/
                }
                if(flag_1s == 1)
                {
                                /*********Task in each 1s interval***********/
                                flag_1s = 0;
                                LED_PORT =! LED_PORT;                //working station indicator
                                /********************************************/
                }
}

//*************************************************************/
//*Function Name:void Delay_5ms(uint delay4msval)
//*Function     :Delay 0~65536*5ms
//*Parameter    :The number of 5ms
//*Return Value :None
//*************************************************************/
void Delay_5ms(uint delay4msval)
{
                while(delay4msval)
                {
                                PCON |= 0X01;
                    --delay4msval;
                          Time_Event();
                }       
}

/*-------------------------------------------------------------*/
/******************************The End**************************/
/*-------------------------------------------------------------*/








使用特权

评论回复
16
黑小子mxx|  楼主 | 2015-5-20 22:30 | 只看该作者
ayb_ice 发表于 2015-5-18 07:53
你主循环是怎么处理的,上代码

我的本意是想用Tick5ms这一个变量就能实现任意长度的时间间隔,如果用标志位的话要浪费掉几个变量。

使用特权

评论回复
17
ayb_ice| | 2015-5-21 08:16 | 只看该作者
黑小子mxx 发表于 2015-5-20 22:30
我的本意是想用Tick5ms这一个变量就能实现任意长度的时间间隔,如果用标志位的话要浪费掉几个变量。 ...

原因很简单,为什么用标志可以呢,直接用变量就不行呢

这是因为变量在中断里改变,主循环第一次读可能没有到达指定时间,第二次去读的时候又过了指定的时间,因这是因为主循环与中断没有同步机制的原因,

但用标志就不同了,因为每中断一次都会在中断判断时间是否到达,到达设标志,这样不会产生遗漏,

了解了本质解决问题很简单,
1: 用标志,
2: 在主循环里对变量加1处理,(设置中断标志,主循环判断标志OK后,主循环执行一遍),推荐此方法
void isr_t0(void) interrupt 1
{
        ....
        isr_flag = 1;
}

void main(void)
{
        ...
        while(1)
        {
                if(isr_flag == 1){
                        isr_flag = 0;

                        if(++counter >= 200){
                                counter = 0;
                        }

                        if(counter == 10){
                                ...
                        }

                        if(counter == 5){
                                ...
                        }
                }

        }
}

使用特权

评论回复
18
gx_huang| | 2015-5-21 08:22 | 只看该作者
LZ呀,既然你不太懂汇编,你就少用汇编和C的混合编程了。
其实,普通应用,不需要汇编的,最多汇编嵌入就可以了,如果你不懂汇编的奥妙,还不如不用,还不如C的效率高呀。

使用特权

评论回复
19
黑小子mxx|  楼主 | 2015-5-21 23:00 | 只看该作者
gx_huang 发表于 2015-5-21 08:22
LZ呀,既然你不太懂汇编,你就少用汇编和C的混合编程了。
其实,普通应用,不需要汇编的,最多汇编嵌入就可 ...

嗯,汇编确实不是很懂,所以在学。我这里用汇编一是想尝试一下混合编程,再就是为了减少代码量。之前用纯C也写了一遍,但是已经超出了8K,主要是OLED模块占用了4K,刚好厂家也提供了汇编程序,代码量小得多。

使用特权

评论回复
20
gx_huang| | 2015-5-22 08:41 | 只看该作者
黑小子mxx 发表于 2015-5-21 23:00
嗯,汇编确实不是很懂,所以在学。我这里用汇编一是想尝试一下混合编程,再就是为了减少代码量。之前用纯 ...

我很早以前,也是用汇编,无线电杂志介绍的武汉HH-51单板机,都20多年了,买了一个,内部有监控程序,专门反汇编解剖别人的程序,学到不少汇编的技巧。不过后来也放弃了,维护太麻烦,时间久了,维护比开发还难。如果你的C代码大了,也许你可以优化C代码的。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

42

主题

307

帖子

2

粉丝