打印

Keil C51汇编转C之烦恼

[复制链接]
6446|18
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
hotpower|  楼主 | 2009-1-21 21:27 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
菜农跳入新部门后看到产品几乎都是用汇编,而且根本不将结构化设计,
也更谈不上面向对象设计,很是倒塌~~~

先是将DSP的C转为C++,又要将很多51汇编程序转为C程序。

看了DSP的C程序后感觉简直就是A人用C,满地的全局变量~~~
更可气的是状态不进行归纳,整个一个“块拷贝”

当有10个相同任务时,先写一个任务,再复制9个任务,随后一次更名任务号及变量号。。。

每个任务都是许多全局变量...实在是倒塌!!!

汇编手法同理,本来不到10个全局变量竟然全部用光,每次增加或修改程序实在无从下手~~~

满地的汇编分支号实在眼晕,看得俺真的呕吐~~~

真不知道当年的老A是如何带出这些“超人”的~~~

下图的C是俺改写的,并增加了许多自检和安全程序,代码用C反而

少了2KByte,速度一点不差,实在是倒塌~~~

本不想再搞51了,看来是被逼无奈了~~~

相关帖子

来自 2楼
hotpower|  楼主 | 2009-1-21 22:21 | 只看该作者

A人之恶习---满地的全局变量

下面的程序很典型~~~全局变量soft_dog_timer
首先不考虑是否合理,若soft_dog_timer是主程序和中断服务程序共有的变量

则建议加volatile修饰全局变量soft_dog_timer

因为全局变量soft_dog_timer是主程序和中断服务程序共有的变量。
uchar可能问题不大,但uint肯定会出数据临界的问题。

若全局变量soft_dog_timer只在某个函数或中断服务程序中使用,
则一个考虑局部变量,若soft_dog_timer要长期生存,则应该考虑

在某个函数或中断服务程序中申请静态的局部变量。

全局变量的最大坏处是在任何地方都可对之修改,故很不安全~~~

所以:A人之恶习---满地的全局变量


例如:(俺对事不对人~~~望Batistuta_谅解之)

Batistuta_ 发表于 2009-1-18 17:50 侃单片机 ←返回版面   举报该贴 

#define    SOFT_DOG_TIME  XX    // xx小于硬件狗溢出时间的一半
bit   **_soft_dog=0;
uchar soft_dog_timer=0;
main()
{
  ... 
  while(1)
  {
     ...
     //-----------------
     **_soft_dog = 0;
     //-----------------
     ... 
  }
}

time_interrupt()    //通用定时器
{
  ...
  //--------------------------
  soft_dog_timer++;
  if(soft_dog_timer>=SOFT_DOG_TIME)
  {
     soft_dog_timer = 0;
  }   
  if(**_soft_dog)
  {
     soft_reset();        //软件复位
  }
  else
  {
     **_soft_dog = 1;
  }
  //--------------------------
  ...    
}
 
 

相关链接:https://bbs.21ic.com/club/bbs/ShowAnnounce.asp?v=&ID=3213530

使用特权

评论回复
板凳
john_light| | 2009-1-21 22:11 | 只看该作者

少年维特的烦恼

再说

使用特权

评论回复
地板
古道热肠| | 2009-1-22 10:03 | 只看该作者

A人还喜欢CJMP满天转

用Call,那太浪费.

使用特权

评论回复
5
古道热肠| | 2009-1-22 10:08 | 只看该作者

最近看了一段A片,速度的确能上去.

; CH375/CH372 Bulk Data Test
; U2(AT89C51) Program
; 本程序测试数据传输的正确性, 并通过收发大数据块来测试传输速度,
; 本程序适用于时钟频率不高于24MHz的标准MCS-51单片机, 如果高于24MHz则应该适当增加延时, 如果低于24MHz则可以适当减少延时
; 只要单片机允许, 尽量使用较高的时钟, 例如将原12MHz晶振换为24MHz,
; 因为MCS51单片机自身速度较慢,读写外部RAM需要2个周期以及附加的循环指令,即使24MHz时钟也无法超过500KB/S
; 为了减少单片机自身对速度测试的影响,本程序中速度测试部分在单片机中断服务程序中完成
;
;
;
; 需要主程序定义的参数
CH375_CMD_PORT        EQU    0B100H         ;CH375命令口的地址,地址译码后自动片选
CH375_DAT_PORT        EQU    0B000H         ;CH375命令口的地址,地址译码后自动片选
;
THIS_CMD_CODE        DATA   3EH            ;保存当前命令码
RECV_LEN            DATA   3FH            ;刚接收到的数据的长度
RECV_BUFFER            DATA   40H            ;数据缓冲区,用于保存接收到的下传数据,长度为0到64字节
; 由于MCS-51单片机存取外部RAM的读写速度低于内部RAM, 并且需要用到DPTR, 所以读写速度较慢, 其程序可以参考本程序修改
;
; 定义位标志
FLAG_RECV_OK        BIT    2FH.0          ;接收成功标志,1指示成功接收到数据块
FLAG_SEND_WAIT        BIT    2FH.1          ;发送等待标志,1指示有数据块正在CH375中等待发送
;
; CH375的命令代码定义
$INCLUDE            (CH375INC.ASM)
;
;****************************************************************************
;
; 应用层定义
;TEST_OTHER        EQU    00H                ;其它自定义的命令码
TEST_START        EQU    20H                ;测试过程开始
TEST_DATA        EQU    21H                ;测试数据正确性
TEST_UPLOAD        EQU    22H                ;测试上传数据块
TEST_DOWNLOAD    EQU    23H                ;测试下传数据块
;
STACK           EQU    0FH             ;堆栈区栈顶(向上延伸)
;
;****************************************************************************
;主程序,用于配合演示CH375
                ORG   0000H            ;复位后单片机入口
                LJMP  START
                ORG   0013H            ;CH375中断
                LJMP  CH375_INTER
;
START:
; 以下初始化指令不是必要的,将单片机恢复为默认状态
                CLR   EA               ;关中断
                MOV   SP,#STACK        ;置堆栈初值
                MOV   A,#0FFH
                MOV   P0,A
                MOV   P1,A             ;清端口状态
                MOV   P2,A
                MOV   P3,A
                CLR   A
                MOV   IE,A             ;清中断允许控制寄存器
                MOV   IP,A             ;清中断优先级控制寄存器
                MOV   PSW,A            ;清程序状态字
                MOV   TCON,A           ;清定时器/计数器控制寄存器
                MOV   TMOD,A           ;清定时器/计数器工作方式寄存器
                MOV   PCON,A           ;清电源控制寄存器
                MOV   THIS_CMD_CODE,#00H ;清除命令码
                MOV   R7,#0FFH
                CALL  DELAY_MS            ;延时等待CH375初始化完成
; 初始化
                CALL  CH375_INIT       ;初始化
;                .....
;
                SETB  EA               ;允许中断
                SETB  TR0                ;由定时器0自由计数值产生随机数
;
; 以下指令开始工作循环,等待PC机命令进行操作
WAIT_REQUEST:    NOP
                JNB   FLAG_RECV_OK,WAIT_REQUEST    ;等待下传数据
                CLR   FLAG_RECV_OK
                MOV   A,RECV_LEN            ;分析下传数据并准备应答
                JZ    WAIT_REQUEST            ;长度为0,在本程序中没有意义
;
; 以毫秒为单位延时
; ENTRY: R7 延时毫秒数
; USE:   ACC, R7
DELAY_MS:        MOV   A,#0FAH                ;250*(1*6+2)*0.5=1000uS
DELAY_1MS:        NOP
                NOP
                NOP
                NOP
                NOP
                NOP
                DJNZ  ACC,DELAY_1MS            ;每周期延时1毫秒
                DJNZ  R7,DELAY_MS
                RET
;
;
;****************************************************************************
;
; 初始化子程序
; USE:   ACC, R7, DPTR
CH375_INIT:        CLR   FLAG_RECV_OK            ;清接收成功标志,1指示成功接收到数据块
                CLR   FLAG_SEND_WAIT        ;清发送等待标志,1指示有数据块正在CH375中等待发送
; 测试CH375是否正常工作,可选操作
;                MOV   DPTR,#CH375_CMD_PORT    ;命令口地址
;                MOV   A,#CMD_CHECK_EXIST
;                MOVX  @DPTR,A                ;测试CH375是否正常工作,可选操作
;                NOP                            ;如果时钟频率低于16MHz则无需该指令延时,高于30MHz要多加2条指令
;                MOV   DPTR,#CH375_DAT_PORT    ;数据口地址
;                MOV   A,#55H
;                MOVX  @DPTR,A                ;写入测试数据
;                CPL   A
;                MOV   R7,A                    ;取反数据
;                MOVX  A,@DPTR                ;返回数据应该是测试数据取反
;                XRL   A,R7
;                JZ    CH375_INIT_OK            ;测试通过
;                MOV   DPTR,#CH375_CMD_PORT    ;命令口地址
;                MOV   A,#CMD_RESET_ALL
;                MOV   R7,#50H                ;多次重复发命令
;CH375_INIT_HR:    MOVX  @DPTR,A                ;执行硬件复位
;                DJNZ  R7,CH375_INIT_HR
;                MOV   R7,#0A0H                ;160*256uS=40mS
;CH375_INIT_D2:    CLR   A
;CH375_INIT_D1:    DJNZ  ACC,CH375_INIT_D1        ;延时1uS
;                DJNZ  R7,CH375_INIT_D2        ;延时256uS
;                SJMP  CH375_INIT            ;再次测试
;CH375_INIT_OK:
; 设置外部自定义的USB设备VID和PID,可选操作,不执行该命令则使用默认的VID和PID
;                MOV   DPTR,#CH375_CMD_PORT    ;命令口地址
;                MOV   A,#CMD_SET_USB_ID
;                MOVX  @DPTR,A                ;设置外部自定义的USB设备VID和PID,可选操作
;                NOP                            ;如果时钟频率低于16MHz则无需该指令延时
;                MOV   DPTR,#CH375_DAT_PORT    ;数据口地址
;                MOV   A,#USB_VENDOR_ID_L
;                MOVX  @DPTR,A                ;写入厂商ID的低字节
;                MOV   A,#USB_VENDOR_ID_H
;                MOVX  @DPTR,A                ;写入厂商ID的高字节
;                MOV   A,#USB_DEVICE_ID_L
;                MOVX  @DPTR,A                ;写入设备ID的低字节
;                MOV   A,#USB_DEVICE_ID_H
;                MOVX  @DPTR,A                ;写入设备ID的高字节
;                NOP
; 设置USB工作模式
                MOV   DPTR,#CH375_CMD_PORT    ;命令口地址
                MOV   A,#CMD_SET_USB_MODE
                MOVX  @DPTR,A                ;设置USB工作模式
                NOP                            ;如果时钟频率低于16MHz则无需该指令延时
                MOV   DPTR,#CH375_DAT_PORT    ;数据口地址
                MOV   A,#02H
                MOVX  @DPTR,A                ;设置为使用内置固件的USB设备方式
                NOP                            ;如果时钟频率低于16MHz则无需该指令延时
        CH375_INIT_WT:    MOVX  A,@DPTR                ;返回操作状态
                XRL   A,#CMD_RET_SUCCESS
                JNZ   CH375_INIT_WT            ;等待操作成功,通常需要等待10uS-20uS
; 下述三条指令用于启用中断
                CLR   IT1                    ;置外部信号为低电平触发
                SETB  PX1                    ;置高优先级
                CLR   IE1                    ;清中断标志
                SETB  EX1                    ;允许CH375中断
                RET
;
; 上传数据块子程序(通过批量端点上传)
; ENTRY: R0 指向存放了准备上传数据的缓冲区, R7 准备上传的数据长度, 有效数值是0到64
; USE:   ACC, R0, R7, DPTR

        CH375_UPLOAD:    JB    FLAG_SEND_WAIT,CH375_UPLOAD    ;如果正在等待发送(前次发送尚未完成)则继续等待
                CLR   EX1                    ;为了防止中途被中断而乱了顺序,必须先禁止中断
                MOV   DPTR,#CH375_CMD_PORT    ;命令口地址
                MOV   A,#CMD_WR_USB_DATA7
                MOVX  @DPTR,A                ;向USB端点2的发送缓冲区写入数据块
                NOP                    ;如果时钟频率低于16MHz则无需该指令延时
                NOP
                MOV   DPTR,#CH375_DAT_PORT    ;数据口地址
                MOV   A,R7
                MOVX  @DPTR,A                ;首先写入后续数据长度

        CH375_UPLOAD_1:    MOV   A,@R0
                INC   R0
                MOVX  @DPTR,A                ;发送数据
                DJNZ  R7,CH375_UPLOAD_1        ;继续发送数据直至结束
                SETB  FLAG_SEND_WAIT        ;置等待发送标志
                SETB  EX1                    ;允许中断
                RET
;
; 上传中断数据子程序(通过中断端点上传),可选子程序
; ENTRY: R0 指向存放了准备上传数据的缓冲区, R7 准备上传的数据长度, 有效数值是0到8
; USE:   ACC, R0, R7, DPTR
        CH375_UP_INT:    CLR   EX1                    ;为了防止中途被中断而乱了顺序,必须先禁止中断
                MOV   DPTR,#CH375_CMD_PORT    ;命令口地址
                MOV   A,#CMD_WR_USB_DATA5
                MOVX  @DPTR,A                ;向USB端点1的发送缓冲区写入数据块
                NOP                            ;如果时钟频率低于16MHz则无需该指令延时
                NOP
                MOV   DPTR,#CH375_DAT_PORT    ;数据口地址
                MOV   A,R7
                MOVX  @DPTR,A                ;首先写入后续数据长度
        CH375_UP_INT_1:    MOV   A,@R0
                INC   R0
                MOVX  @DPTR,A                ;发送中断数据
                DJNZ  R7,CH375_UP_INT_1        ;继续发送数据直至结束
                SETB  EX1                    ;允许中断
                RET
;
; 中断服务子程序
; USE:   堆栈8字节
        CH375_INTER:    PUSH  PSW                    ;现场保护
                PUSH  ACC
                PUSH  DPL
                PUSH  DPH
;                PUSH  01H                    ;R1
;                PUSH  02H                    ;R2
;主程序中未使用R1/R2,所以不必入栈保护,从而提高速度
                MOV   DPTR,#CH375_CMD_PORT    ;命令口地址
                MOV   A,#CMD_GET_STATUS
                MOVX  @DPTR,A                ;获取中断状态并取消中断请求
                NOP                            ;如果时钟频率低于16MHz则无需该指令延时,高于30MHz要多加2条指令
                NOP
                NOP
; 单片机向写CH375写入命令码后,应该要等2uS才能读取数据,所以时钟频率高于16MHz时需要指令延时
                MOV   DPTR,#CH375_DAT_PORT    ;数据口地址
                MOVX  A,@DPTR                ;返回操作状态
                CLR   IE1                    ;清中断标志,对应于INT0中断
                CJNE  A,#USB_INT_EP2_OUT,CH375_INT_1    ;批量端点下传成功
                LJMP  CH375_DOWN_OK            ; USB批量数据接收成功

        CH375_INT_1:    CJNE  A,#USB_INT_EP2_IN,CH375_INT_2    ;批量端点上传成功
                LJMP  CH375_UP_OK            ; USB批量数据发送成功

        CH375_INT_2:    CJNE  A,#USB_INT_EP1_IN,CH375_INT_3    ;中断端点
                LJMP  CH375_UP_INT_OK        ; USB中断数据发送成功

        CH375_INT_3:    SJMP  CH375_INT_RET

        CH375_INT_RET:
;                POP   02H                    ;R2
;                POP   01H                    ;R1
                POP   DPH
                POP   DPL
                POP   ACC
                POP   PSW                    ;恢复寄存器
                RETI                        ;中断返回
;
        CH375_DOWN_OK:    ; USB批量数据接收成功
                MOV   DPTR,#CH375_CMD_PORT    ;命令口地址
                MOV   A,#CMD_RD_USB_DATA
                MOVX  @DPTR,A                ;从当前USB中断的端点缓冲区读取数据块,并释放缓冲区
                NOP                            ;如果时钟频率低于16MHz则无需该指令延时,高于30MHz要多加一条指令
                NOP
; 单片机向写CH375写入命令码后,应该要等2uS才能读取数据,所以时钟频率高于16MHz时需要指令延时
                MOV   DPTR,#CH375_DAT_PORT    ;数据口地址
                
                MOVX  A,@DPTR                ;首先读取后续数据长度
                MOV   R2,A
                JZ    CH375_INT_RET            ;长度为0,没有数据则直接退出

                MOVX  A,@DPTR                ;接收数据
                MOV   THIS_CMD_CODE,A        ;保存当前命令码

                CJNE  A,#TEST_DOWNLOAD,IS_USB_CMD0
                SJMP  USB_CMD2_NEXT            ;测试下传速度

        USB_CMD2_RECV:    MOVX  A,@DPTR                ;接收数据,为了测试速度,数据舍弃,24MHz的MCS51每读取一个字节需要2uS
        USB_CMD2_NEXT:    DJNZ  R2,USB_CMD2_RECV        ;继续接收数据直至结束
                SJMP  CH375_INT_RET

        IS_USB_CMD0:    MOV   R1,#RECV_BUFFER        ;接收缓冲区
                MOV   RECV_LEN,R2
                SJMP  CH375_INT_RECV0

        CH375_INT_RECV:    MOVX  A,@DPTR                ;接收数据
    CH375_INT_RECV0:    MOV   @R1,A
                INC   R1
                DJNZ  R2,CH375_INT_RECV        ;继续接收数据直至结束

                MOV   A,RECV_BUFFER            ;首字节是命令码
                CJNE  A,#TEST_UPLOAD,IS_USB_CMD3

        USB_CMD3_NEXT:    ;测试上传速度
                MOV   DPTR,#CH375_CMD_PORT    ;命令口地址
                MOV   A,#CMD_WR_USB_DATA7
                MOVX  @DPTR,A                ;向USB端点2的发送缓冲区写入数据块
                NOP                            ;如果时钟频率低于16MHz则无需该指令延时
                NOP
                MOV   DPTR,#CH375_DAT_PORT    ;数据口地址
                MOV   A,#40H
                MOVX  @DPTR,A                ;首先写入后续数据长度

                MOV   R7,A
                MOV   A,TL0                    ;随机数
        USB_CMD3_SEND:    MOVX  @DPTR,A                ;发送数据,为了测试速度,数据无效,24MHz的MCS51每写出一个字节需要2uS
                DJNZ  R7,USB_CMD3_SEND        ;继续发送数据直至结束
                SJMP  CH375_INT_UNLK

        IS_USB_CMD3:    CJNE  A,#TEST_START,IS_USB_CMD1
                NOP                            ;测试过程开始
; 由于上一次测试数据上传速度时可能在上传缓冲区中遗留有数据, 所以在第二次测试前需要清除上传缓冲区
                MOV   DPTR,#CH375_CMD_PORT    ;命令口地址
                MOV   A,#CMD_SET_ENDP7
                MOVX  @DPTR,A                ;设置USB端点2的IN
                NOP                            ;如果时钟频率低于16MHz则无需该指令延时
                NOP
                MOV   DPTR,#CH375_DAT_PORT    ;数据口地址
                MOV   A,#0EH                ;同步触发位不变
                MOVX  @DPTR,A                ;设置USB端点2的IN正忙,返回NAK
                CLR   FLAG_SEND_WAIT        ;清除发送等待标志,通知应用程序可以继续发送数据
                LJMP  CH375_INT_RET

        IS_USB_CMD1:    CJNE  A,#TEST_DATA,IS_USB_CMD9
                NOP                            ;测试数据正确性
                MOV   DPTR,#CH375_CMD_PORT    ;命令口地址
                MOV   A,#CMD_WR_USB_DATA7
                MOVX  @DPTR,A                ;向USB端点2的发送缓冲区写入数据块
                NOP
                NOP                            ;如果时钟频率低于16MHz则无需该指令延时
                MOV   DPTR,#CH375_DAT_PORT    ;数据口地址
                MOV   A,RECV_LEN
                MOVX  @DPTR,A                ;首先写入后续数据长度

                MOV   R2,A                    ;刚接收到的数据长度
                MOV   R1,#RECV_BUFFER        ;刚接收到的数据块
        USB_CMD1_NEXT:    MOV   A,@R1
                CPL   A                        ;数据取反后返回,由计算机应用程序测试数据是否正确
                MOVX  @DPTR,A                ;发送数据
                INC   R1
                DJNZ  R2,USB_CMD1_NEXT

                LJMP  CH375_INT_RET

        IS_USB_CMD9:    SETB  FLAG_RECV_OK            ;其它命令,设置接收成功标志,通知应用程序取走数据再分析
                LJMP  CH375_INT_RET
;
        CH375_UP_OK:    ; USB批量数据发送成功
                MOV   A,THIS_CMD_CODE
                CJNE  A,#TEST_UPLOAD,CH375_INT_UNLK
                SJMP  USB_CMD3_NEXT            ;测试上传速度,继续准备上传数据

        CH375_INT_UNLK:    MOV   DPTR,#CH375_CMD_PORT    ;命令口地址
                MOV   A,#CMD_UNLOCK_USB
                MOVX  @DPTR,A                ;释放当前USB缓冲区
                CLR   FLAG_SEND_WAIT        ;清除发送等待标志,通知应用程序可以继续发送数据
                LJMP  CH375_INT_RET
;
        CH375_UP_INT_OK:    ; USB中断数据发送成功
                MOV   DPTR,#CH375_CMD_PORT    ;命令口地址
                MOV   A,#CMD_UNLOCK_USB
                MOVX  @DPTR,A                ;释放当前USB缓冲区
                LJMP  CH375_INT_RET
;
;
END

相关链接:https://bbs.21ic.com/upfiles/img/20091/200912210252512.rar

使用特权

评论回复
6
古道热肠| | 2009-1-22 10:13 | 只看该作者

同样的功能用C片适合大众口味,速度下降一半

/*
; CH375/CH372 Bulk Data Test
; U2(AT89C51) Program
; 本程序测试数据传输的正确性, 并通过收发大数据块来测试传输速度,
; 本程序适用于时钟频率不高于24MHz的标准MCS-51单片机, 如果高于24MHz则应该适当增加延时, 如果低于24MHz则可以适当减少延时
; 只要单片机允许, 尽量使用较高的时钟, 例如将原12MHz晶振换为24MHz,
; 因为MCS51单片机自身速度较慢,读写外部RAM需要2个周期以及附加的循环指令,即使24MHz时钟也无法超过500KB/S
; 为了减少单片机自身对速度测试的影响,本程序中速度测试部分在单片机中断服务程序中完成

/* MCS-51单片机C语言的示例程序 */

#include <reg52.h>
#include <string.h>
#include "CH375INC.H"

/* #define USE_MY_USB_ID    YES */
#define MY_USB_VENDOR_ID    0x1234        /* 厂商ID */
#define MY_USB_DEVICE_ID    0x5678        /* 设备ID */

unsigned char volatile xdata CH375_CMD_PORT _at_ 0xB100;        /* CH375命令端口的I/O地址 */
unsigned char volatile xdata CH375_DAT_PORT _at_ 0xB000;        /* CH375数据端口的I/O地址 */

unsigned char THIS_CMD_CODE;  /* 保存当前命令码 */
unsigned char RECV_LEN;       /* 刚接收到的数据的长度 */
unsigned char RECV_BUFFER[ CH375_MAX_DATA_LEN ];  /* 数据缓冲区,用于保存接收到的下传数据,长度为0到64字节 */
/* 由于MCS-51单片机存取外部RAM的读写速度低于内部RAM, 并且需要用到DPTR, 所以读写速度较慢, 其程序可以参考本程序修改 */

/* 定义位标志 */
bit bdata FLAG_RECV_OK;       /* 接收成功标志,1指示成功接收到数据块 */
bit bdata FLAG_SEND_WAIT;     /* 发送等待标志,1指示有数据块正在CH375中等待发送 */

/* 应用层定义 */
/* TEST_OTHER        EQU    00H                ;其它自定义的命令码 */
#define TEST_START        0x20  /* 测试过程开始 */
#define TEST_DATA        0x21  /* 测试数据正确性 */
#define TEST_UPLOAD        0x22  /* 测试上传数据块 */
#define TEST_DOWNLOAD    0x23  /* 测试下传数据块 */

/* 有关CH451的定义,演示板的连接方式,该程序没有用到键盘 */
sbit   CH451_dclk=P1^7;      /* 串行数据时钟上升延激活 */
sbit   CH451_din=P1^6;         /* 串行数据输出,接CH451的数据输入 */
sbit   CH451_load=P1^5;      /* 串行命令加载,上升延激活 */

/* 延时2微秒,不精确 */
void    Delay2us( )
{
    unsigned char i;
#define DELAY_START_VALUE    1  /* 根据单片机的时钟选择初值,20MHz以下为0,30MHz以上为2 */
    for ( i=DELAY_START_VALUE; i!=0; i-- );
}

/* 延时50毫秒,不精确 */
void    Delay50ms( )
{
    unsigned char i, j;
    for ( i=200; i!=0; i-- ) for ( j=250; j!=0; j-- );
}

/* CH375初始化子程序 */
void    CH375_Init( )
{
    unsigned char i;
    FLAG_RECV_OK=0;  /* 清接收成功标志,1指示成功接收到数据块 */
    FLAG_SEND_WAIT=0;  /* 清发送等待标志,1指示有数据块正在CH375中等待发送 */
/* 测试CH375是否正常工作,可选操作,通常不需要 */
#ifdef TEST_CH375_FIRST
    CH375_CMD_PORT = CMD_CHECK_EXIST;  /* 测试CH375是否正常工作 */
    Delay2us( );  /* 如果时钟频率低于16MHz则无需该指令延时 */
    CH375_DAT_PORT = 0x55;  /* 写入测试数据 */
    Delay2us( );
    i = ~ 0x55;  /* 返回数据应该是测试数据取反 */
    if ( CH375_DAT_PORT != i ) {  /* CH375不正常 */
        for ( i=80; i!=0; i-- ) {
            CH375_CMD_PORT = CMD_RESET_ALL;  /* 多次重复发命令,执行硬件复位 */
            Delay2us( );
        }
        CH375_CMD_PORT = 0;
        Delay50ms( );  /* 延时50ms */
    }
#endif
#ifdef USE_MY_USB_ID
/* 设置外部自定义的USB设备VID和PID,可选操作,不执行该命令则使用默认的VID和PID */
    CH375_CMD_PORT = CMD_SET_USB_ID;  /* 设置外部自定义的USB设备VID和PID,可选操作 */
    Delay2us( );  /* 如果时钟频率低于16MHz则无需该指令延时 */
    CH375_DAT_PORT = (unsigned char)MY_USB_VENDOR_ID;  /* 写入厂商ID的低字节 */
    CH375_DAT_PORT = (unsigned char)(MY_USB_VENDOR_ID>>8);  /* 写入厂商ID的高字节 */
    CH375_DAT_PORT = (unsigned char)MY_USB_DEVICE_ID;  /* 写入设备ID的低字节 */
    CH375_DAT_PORT = (unsigned char)(MY_USB_DEVICE_ID>>8);  /* 写入设备ID的高字节 */
    Delay2us( );
#endif
/* 设置USB工作模式, 必要操作 */
    CH375_CMD_PORT = CMD_SET_USB_MODE;
    Delay2us( );  /* 如果时钟频率低于16MHz则无需该指令延时 */
    CH375_DAT_PORT = 2;  /* 设置为使用内置固件的USB设备方式 */
    for ( i=100; i!=0; i-- ) {  /* 等待操作成功,通常需要等待10uS-20uS */
        if ( CH375_DAT_PORT==CMD_RET_SUCCESS ) break;
    }
/*    if ( i==0 ) { CH372/CH375存在硬件错误 }; */
/* 下述启用中断,假定CH375连接在INT0 */
    IT1 = 0;  /* 置外部信号为低电平触发 */
    IE1 = 0;  /* 清中断标志 */
    EX1 = 1;  /* 允许CH375中断 */
}

/* CH375中断服务程序,使用寄存器组1 */
void    mCh375Interrupt( ) interrupt 2 using 1
{
    unsigned char InterruptStatus;
    unsigned char length, c1;
    unsigned char data *cmd_buf;
    unsigned char data *ret_buf;
    CH375_CMD_PORT = CMD_GET_STATUS;  /* 获取中断状态并取消中断请求 */
    Delay2us( );  /* 如果时钟频率低于16MHz则无需该指令延时 */
    InterruptStatus = CH375_DAT_PORT;  /* 获取中断状态 */
    IE1 = 0;  /* 清中断标志,对应于INT1中断 */
    if ( InterruptStatus == USB_INT_EP2_OUT ) {  /* 批量端点下传成功 */
        CH375_CMD_PORT = CMD_RD_USB_DATA;  /* 从当前USB中断的端点缓冲区读取数据块,并释放缓冲区 */
        Delay2us( );  /* 如果时钟频率低于16MHz则无需该指令延时 */
        length = CH375_DAT_PORT;  /* 首先读取后续数据长度 */
        if ( length != 0 ) 
        {  /* 如果长度为0则不处理 */
            THIS_CMD_CODE = CH375_DAT_PORT;  /* 保存当前命令码,因为我们测试程序与PC机应用程序约定首字节为命令码 */
            if ( THIS_CMD_CODE == TEST_DOWNLOAD )
             {  /* 测试下传速度 */
                while ( --length != 0 )  /* 先减1以去掉首字节后 */
                    c1 = CH375_DAT_PORT;  /* 接收数据,为了测试速度,数据舍弃,24MHz的MCS51每读取一个字节需要2uS */
            }
            else 
            {  /* 不是测试下传速度的命令,先接收完命令包再分析 */
                RECV_LEN = length;  /* 命令包的数据长度 */
                cmd_buf = RECV_BUFFER;  /* 接收缓冲区 */
                *cmd_buf = THIS_CMD_CODE;
                while ( --length != 0 ) 
                {  /* 先减1以去掉首字节后 */
                    cmd_buf++;
                    *cmd_buf = CH375_DAT_PORT;
                }
/* 以上程序C语言要每读一个字节可能要十多个机器周期,如果用汇编语言只要4个机器周期
                    mov  a,length
                    jz   skip_get
                    mov  r7,a
                    mov  dptr,#CH375_DAT_PORT
get_next_byte:        movx a,@dptr    数据直接放弃
                    djnz r7,get_next_byte
skip_get:            nop
*/
                if ( THIS_CMD_CODE == TEST_UPLOAD ) 
                {  /* 测试上传速度 */
                    CH375_CMD_PORT = CMD_WR_USB_DATA7;  /* 向USB端点2的发送缓冲区写入数据块 */
                    Delay2us( );  /* 如果时钟频率低于16MHz则无需该指令延时 */
                    length = CH375_MAX_DATA_LEN;
                    CH375_DAT_PORT = length;  /* 首先写入后续数据长度 */
                    do {
                        CH375_DAT_PORT = TL0;  /* 发送伪随机数数据,为了测试速度,数据无效,24MHz的MCS51每写出一个字节需要2uS */
                    } while ( --length != 0 );
                }
                else if ( THIS_CMD_CODE == TEST_START ) 
                {  /* 测试过程开始 */
/* 由于上一次测试数据上传速度时可能在上传缓冲区中遗留有数据, 所以在第二次测试前需要清除上传缓冲区 */
                    CH375_CMD_PORT = CMD_SET_ENDP7;  /* 设置USB端点2的IN */
                    Delay2us( );  /* 如果时钟频率低于16MHz则无需该指令延时 */
                    CH375_DAT_PORT = 0x0e;  /* 同步触发位不变,设置USB端点2的IN正忙,返回NAK */
                    FLAG_SEND_WAIT = 0;  /* 清除发送等待标志,通知应用程序可以继续发送数据 */
                }
                else if 
                ( THIS_CMD_CODE == TEST_DATA ) {  /* 测试数据正确性,将接收到的命令包数据取反后返回给PC机 */
                    CH375_CMD_PORT = CMD_WR_USB_DATA7;  /* 向USB端点2的发送缓冲区写入数据块 */
                    Delay2us( );  /* 如果时钟频率低于16MHz则无需该指令延时 */
                    ret_buf = RECV_BUFFER;  /* 接收缓冲区 */
                    length = RECV_LEN;  /* 刚接收到的数据长度 */
                    CH375_DAT_PORT = length;  /* 首先写入后续数据长度 */
                    if ( length ) {
                        do {
                            CH375_DAT_PORT = ~ *ret_buf;  /* 数据取反后返回,由计算机应用程序测试数据是否正确 */
                            ret_buf++;
                        } while ( --length != 0 );
                    }
                }
                else {  /* 其它命令,尚未定义 */
                    FLAG_RECV_OK = 1;  /* 其它命令,设置接收成功标志,通知应用程序取走数据再分析 */
                }
            }
        }
    }
    else if ( InterruptStatus == USB_INT_EP2_IN ) 
    {  /* 批量数据发送成功 */
        if ( THIS_CMD_CODE == TEST_UPLOAD ) {  /* 测试上传速度,继续准备上传数据 */
            CH375_CMD_PORT = CMD_WR_USB_DATA7;  /* 向USB端点2的发送缓冲区写入数据块 */
            Delay2us( );  /* 如果时钟频率低于16MHz则无需该指令延时 */
            length = CH375_MAX_DATA_LEN;
            CH375_DAT_PORT = length;  /* 首先写入后续数据长度 */
            do {
                CH375_DAT_PORT = TL0;  /* 发送伪随机数数据,为了测试速度,数据无效,24MHz的MCS51每写出一个字节需要2uS */
            } while ( --length != 0 );
        }
        CH375_CMD_PORT = CMD_UNLOCK_USB;  /* 释放当前USB缓冲区 */
        FLAG_SEND_WAIT = 1;  /* 清除发送等待标志,通知应用程序可以继续发送数据 */
    }
    else if ( InterruptStatus == USB_INT_EP1_IN ) {  /* 中断数据发送成功 */
        CH375_CMD_PORT = CMD_UNLOCK_USB;  /* 释放当前USB缓冲区 */
    }
    else {  /* 内置固件的USB方式下不应该出现其它中断状态 */
    }
}

main( ) {
//    unsigned char i;
    Delay50ms( );    /* 延时等待CH375初始化完成,如果单片机由CH375提供复位信号则不必延时 */
    CH375_Init( );  /* 初始化CH375 */
    EA = 1;  /* 允许中断 */
    TR0 = 1;  /* 由定时器0自由计数值产生伪随机数 */
    while ( 1 ) {  /* 以下指令开始工作循环,等待PC机命令进行操作 */
        if ( FLAG_RECV_OK ) {  /* 收到未定义的命令 */
        }
    }
}
相关链接:https://bbs.21ic.com/upfiles/img/20091/200912210830715.rar

使用特权

评论回复
7
yuri714| | 2009-1-22 10:36 | 只看该作者

哇~

A片真可怕。。。

使用特权

评论回复
8
computer00| | 2009-1-22 10:59 | 只看该作者

再优化,嘿嘿...

使用特权

评论回复
9
phoenixmy| | 2009-1-22 12:55 | 只看该作者

咋又开始改51程序了???



这里也有用keil C51编译器
真是倒塌

本以为这里都全部用arm了

使用特权

评论回复
10
Batistuta_| | 2009-1-22 13:22 | 只看该作者

hehe , 俺确实以前用汇编。 汇编没学到家,就玩C

了。。。

谢谢大叔的点评。俺记下了/

"
则建议加volatile修饰全局变量soft_dog_timer

因为全局变量soft_dog_timer是主程序和中断服务程序共有的变量。
uchar可能问题不大,但uint肯定会出数据临界的问题。

若全局变量soft_dog_timer只在某个函数或中断服务程序中使用,
则一个考虑局部变量,若soft_dog_timer要长期生存,则应该考虑

在某个函数或中断服务程序中申请静态的局部变量。

全局变量的最大坏处是在任何地方都可对之修改,故很不安全~~~

"
大叔提到的临界问题俺印象深刻,当时仪器偶尔运行不对,回到家对着程序发呆半天,突然发现出了这种问题。

使用特权

评论回复
11
宇宙飞船| | 2009-1-22 14:58 | 只看该作者

俺虽然也用C,但最爱还是A片!

A片能人所不能,做别人不敢想不敢做的事;

使用特权

评论回复
12
dengm| | 2009-1-22 19:34 | 只看该作者

先重写 “超人”的A, 再转为“超超人” C

使用特权

评论回复
13
airwill| | 2009-1-22 20:13 | 只看该作者

重入魔道的感觉呀

使用特权

评论回复
14
hotpower|  楼主 | 2009-1-23 16:45 | 只看该作者

哈哈~~~将2种板型自动识别只占4KByte

哈哈~~~再也不为何种板用何种程序发愁了~~~

总之再A人也要考虑大局~~~

使用特权

评论回复
15
宇宙飞船| | 2009-1-25 20:51 | 只看该作者

如果跟速度没啥关系的用C也太落后了,

或直用JAVA,C++,又或者用VB,再或者用matlab,最后啥都不用学了,就等别人写
好了底层模块再做下去。再最后就是转行不搞技术了,哈哈。
 

使用特权

评论回复
16
phoenixmy| | 2009-1-25 20:54 | 只看该作者

牛~~~



楼上大过年的还在回答问题,敬业~~~~~~

使用特权

评论回复
17
hotpower|  楼主 | 2009-1-25 21:32 | 只看该作者

哈哈~~~这些俺都会1点~~~

使用特权

评论回复
18
呆板书生| | 2009-1-26 08:00 | 只看该作者

牛呀

使用特权

评论回复
19
宇宙飞船| | 2009-1-26 11:47 | 只看该作者

知道8位单片机AVR的16位带符号数乘法运算的时间是多少吗?

16M 晶振仅用了 1.6 us < 2 us

使用特权

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

本版积分规则

1460

主题

21619

帖子

506

粉丝