搜索
bottom↓
回复: 43

发布一个原创的 AVR 多任务调度系统

[复制链接]

出0入0汤圆

发表于 2006-12-29 04:41:17 | 显示全部楼层 |阅读模式
请感兴趣的测试一下, 并欢迎到我的blog探讨

hoodng.cublog.cn





点击此处下载armok01139337.zip




-----此内容被hoodng于2006-12-29,04:44:10编辑过

阿莫论坛20周年了!感谢大家的支持与爱护!!

月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!

出0入0汤圆

发表于 2006-12-29 08:59:02 | 显示全部楼层
楼主用的 emacs? 不错不错, 正想学习呢.

出0入42汤圆

发表于 2006-12-29 09:14:10 | 显示全部楼层
研究一下,谢谢楼主

出0入0汤圆

 楼主| 发表于 2006-12-29 12:13:55 | 显示全部楼层
我还以为我的帽子被摘了,所以又发了2贴,请版主整理一下。



老外开源,我们也应该开源才能提高水平。

请多指教。

出0入0汤圆

 楼主| 发表于 2006-12-29 12:22:18 | 显示全部楼层
等回帖数到达100时,我将整理和发布设计过程,一方面方便和感兴趣的人共同探讨,最主要的还是为自己的设计在网络上留一个不怕硬盘崩掉的备份:)

出0入0汤圆

发表于 2006-12-29 12:25:37 | 显示全部楼层
很有兴趣,等楼主的

出0入0汤圆

 楼主| 发表于 2007-1-17 22:03:34 | 显示全部楼层
也不知道,我上次放到网上的1.0有没有人看,不管怎么说,在那个1.0的基础上做了3个项目,发现很多问题,所以这一次又加入了SPI的驱动,做个1.1先放上来。

点击此处下载armok01141961.zip

出0入0汤圆

发表于 2007-1-18 00:24:33 | 显示全部楼层
顶一下~~~

正在学习EMACS中~~

出0入0汤圆

发表于 2007-1-18 08:49:41 | 显示全部楼层
谢谢楼主!!!

出0入0汤圆

发表于 2007-1-18 09:06:23 | 显示全部楼层
多谢楼主共享

出0入0汤圆

发表于 2007-1-18 10:56:20 | 显示全部楼层
正在研究中..........

出0入0汤圆

发表于 2007-1-18 11:54:58 | 显示全部楼层
多谢楼主

出0入8汤圆

发表于 2007-1-18 12:15:44 | 显示全部楼层
xuexi

出0入0汤圆

发表于 2007-1-18 12:41:35 | 显示全部楼层
多谢楼主

出0入0汤圆

发表于 2007-1-18 17:23:11 | 显示全部楼层
楼主可看看avrx嘛。

出0入0汤圆

 楼主| 发表于 2007-1-18 22:44:02 | 显示全部楼层
我的这个取名叫AvrcX,和AvrX也算是有某种渊源了,哈哈。

不过要看懂一个操作系统,还是自己写一个吧,对单片机这种有限资源的构架,自己写一个还是很有可能的。

现在加入了SPI的驱动,更改了一些错误,升级到AvrcX1.1,大家有兴趣,再看看。

点击此处下载armok01142099.zip

出0入0汤圆

发表于 2007-1-22 18:24:03 | 显示全部楼层
好東東,頂一下.

出0入0汤圆

发表于 2007-4-14 12:13:21 | 显示全部楼层
顶你一下,别因为回贴人少而放弃。

出0入0汤圆

发表于 2007-4-14 13:33:43 | 显示全部楼层
支持!

出0入0汤圆

发表于 2007-4-14 17:33:00 | 显示全部楼层
我也顶!!!

出0入0汤圆

发表于 2007-4-14 19:21:22 | 显示全部楼层
想请教一下站内的高手:

我也写过类似的,只是我的目的非常非常简单,任务静态创建、调度、挂起、延时就可以了,任务堆栈是静态分布的,编译器是GCC,现在的问题是出现堆栈溢出,我发现的原因是堆栈重叠,调整任务的静态堆栈的大小在一定程度上可以解决这个问题,但单片机的资源是有限的,动态堆栈不知道能不能解决这个问题,而且现在也不知道怎么去实现动态堆栈了

出0入0汤圆

发表于 2007-4-14 20:33:07 | 显示全部楼层
强顶

出0入0汤圆

发表于 2007-4-15 07:11:22 | 显示全部楼层
强东东!顶一下!

出0入0汤圆

发表于 2007-4-15 13:11:44 | 显示全部楼层
现在在试着用AVRX,向楼主学习!

出0入0汤圆

发表于 2007-4-15 16:11:34 | 显示全部楼层
多谢楼住分享

出0入0汤圆

发表于 2007-4-15 23:56:36 | 显示全部楼层
这么强的东东!路过一定要顶上去!像fans一样支持一下!

出0入0汤圆

发表于 2007-5-13 16:32:09 | 显示全部楼层
强烈支持,牛人,继续

出0入0汤圆

发表于 2007-5-14 12:52:46 | 显示全部楼层
顶一下 顶一下

出0入0汤圆

发表于 2007-5-14 13:41:21 | 显示全部楼层
我是新手,虽然有点看不懂,但还是要支持!!

出0入0汤圆

发表于 2007-5-14 19:16:59 | 显示全部楼层
牛人,支持一下先

出0入0汤圆

发表于 2007-5-15 08:52:26 | 显示全部楼层
楼主多发点系统的解析可能更多人感兴趣,否则没有文档的话,估计难有人花时间去钻研代码.

出0入0汤圆

发表于 2007-5-15 18:37:00 | 显示全部楼层
下來看了,還不錯,要是有些實例就更好了,以更方便大家使用與研究.

出0入0汤圆

发表于 2007-5-15 20:16:10 | 显示全部楼层
对这个还不是很懂作用,但是还是值得尊重的!

出0入0汤圆

 楼主| 发表于 2007-7-1 17:44:07 | 显示全部楼层
/**

* Rx complete interrupt handler

*/

void NAKED SIG_UART_RECV(void);

void SIG_UART_RECV(void){

  into_critical();



  prologue();



  if (!(uart.status & UART_RECVDATA)){

    uart.status |= UART_RECVDATA;

    if (uart.hook != NULL) uart.hook(uart.status);

  }



  if (!(UCSRA & (_BV(FE) | _BV(DOR)))){

    unsigned char b = UDR;

    int err = fifo_putbyte(uart.rxbuf, b);

    if (err == -1){

      uart.status |= UART_RX_FULLY;

      if (uart.hook != NULL) uart.hook(uart.status);

    }

  }



  epilogue();

}



应改为:



/**

* Rx complete interrupt handler

*/

void NAKED SIG_UART_RECV(void);

void SIG_UART_RECV(void){

  into_critical();



  prologue();



  if (!(uart.status & UART_RECVDATA)){

    uart.status |= UART_RECVDATA;

    if (uart.hook != NULL) uart.hook(uart.status);

  }



  unsigned char tmp = UCSRA;

  unsigned char b = UDR;

  if (!(tmp & (_BV(FE) | _BV(DOR)))){

    unsigned char b = UDR;

    int err = fifo_putbyte(uart.rxbuf, b);

    if (err == -1){

      uart.status |= UART_RX_FULLY;

      if (uart.hook != NULL) uart.hook(uart.status);

    }

  }



  epilogue();

}



原来的代码在出现祯错误或奇偶错后,没有读UDR来消除错误,这样通常会在通信电缆插拔时带来意想不到的问题。



出0入0汤圆

 楼主| 发表于 2007-7-2 23:32:28 | 显示全部楼层
先从简单的介绍起吧

出0入0汤圆

 楼主| 发表于 2007-7-2 23:32:56 | 显示全部楼层
感谢大家有兴趣关注这个主题,我就尝试写一点系统的解析吧,刚好今天翻看关于"串口通信" RS485方面的主题,看到好多人都贡献了自己成功的串口通信代码,但这些代码也许算法上是不错的,但感觉上系统的结构和移植性等就可以有仁者见仁,智者见智的说辞了。

我先从串口通信的设计部分开始吧,这部分之所以先开始,一是我有了上面所说的感觉,另外呢我调单片机程序基本上都是靠在串口上print信息来调的。



以下是我关于串口设计的思想:

1,基本上一个通信口的程序,因该属于驱动一级的,也就是说它不应该涉及你具体应用的业务逻辑,它只是负责接收数据,或发送你提交的数据。而具体数据的处理由应用层次的代码来解决。

2,对于多任务系统(前后台系统也如此),有可能会有多个任务企图占用串口作输出,如何处理这种竞争。

3,采用面向对象(OO)的设计方法,提高代码的利用率。

4,代码的可重入性,这对多任务来说是必须的。



具体设计:

基于以上4条,我其实最先构筑的是一个Queue对象,而不是串口通信方面的东西,这个数据结构很重要,有着很广泛的用途,比如可以用来实现消息队列,用来处理键盘(红外)来的按键序列等。当然我不会考虑想真正操作系统那样的Queue,我这里实现的只是一个通用的基于字节 FIFO。请看我的bfifo.h文件(修改过,为方便理解去掉了多任务的同步机制)



/**

* Copyright (c) 2006-2008 iWESUN Inf.

* All rights reserved.

*

* File: bfifo.h

* Author: Hu Dong  <hoodng@hotmail.com>

* Create: Jun 22, 2007

*/





#ifndef __BYTEFIFO_H__

#define __BYTEFIFO_H__



#include "common.h"



#define FIFO_IS_EMPTY 1

#define FIFO_IS_FULLY 2



#ifndef __ASSEMBLER__

/* These only work in C program */



typedef struct ByteFifo {

  __volatile__ unsigned char  status;

  unsigned char  mxsize;                 // The max capability

  __volatile__ unsigned char  readps;    // The Read pointer

  __volatile__ unsigned char  writps;    // The Write pointer

  unsigned char *buffer;

} ByteFifo;



/**

* A macro to ease the declaration of ByeFifo definition.

* USAGE: BYTEFIFO(uart_tx, 16);

*

* @param name, The name of the ByteFifo

* @param mxsize, The max capability of the Fifo

*/

#define BYTEFIFO(name, mxsize)                    \

  unsigned char name##_fifo[mxsize];                  \

  ByteFifo name = {                                  \

    FIFO_IS_EMPTY, mxsize, 0, 0,                  \

    &name##_fifo[0]                                  \

  }



/**

* Test whether the fifo is fully

*

* @param ByteFifo*, The pointer to the ByteFifo

* @return bool, TRUE: fully, FALSE: not fully

*/

INTERFACE bool is_fully(ByteFifo*);



/**

* Test whether the fifo is empty

*

* @param ByteFifo*, The pointer to the ByteFifo

* @return bool, TRUE: empty, FALSE: not empty

*/

INTERFACE bool is_empty(ByteFifo*);



/**

* Get a byte from byte fifo

* Return -1 if fifo is empty

*

* @param ByteFifo*, The pointer to the fifo

* @return int, the data. -1 means fifo is empty

*/

INTERFACE int get_byte(ByteFifo*);



/**

* Put a byte to byte fifo

* Return -1 if fifo is fully

*

* @param ByteFifo*, The pointer to the fifo

* @param unsigned char, the byte need to put

* @return int, the byte had put into fifo, -1 means fifo is fully

*/

INTERFACE int put_byte(ByteFifo*, unsigned char);



/**

* Clear byte fifo

* @param ByteFifo*, The pointer to the fifo

*/

INTERFACE void clear_fifo(ByteFifo*);



#endif /* !__ASSEMBLER__ */





#endif /* __BYTEFIFO_H__ */



以上基本上描绘了一个FIFO具有的功能,从方法的签名上可以看出代码是能够重入的,也就是说在系统可以在需要的地方创建很多个FIFO,而它们都可以共享同样的代码。

多说几句,看了论坛上好多人的代码,好像都不是很重视头文件(有人拍砖吗?),其实头文件表明的就是体现你的设计思想,记得有一次听一个搞Java的老外说,他们如何验收一个软件的设计,主要看人家的接口定义如何。而我理解C/C++的头文件就是一个对象的接口定义。



再看一下这个FIFO的具体实现:(修改过,为方便理解去掉了多任务的同步机制)



/**

* Copyright (c) 2006-2008 iWESUN Inf.

* All rights reserved.

*

* File: bfifo.c

* Author: Hu Dong <hoodng@hotmail.com>

* Create: Jun 22, 2007

*

*/



#include "bfifo.h"



/**

* Test whether the fifo is fully

*

* @param ByteFifo*, The pointer to the ByteFifo

* @return bool, TRUE: fully, FALSE: not fully

*/

bool is_fully(ByteFifo* pFifo){

  return (pFifo->status & FIFO_IS_FULLY) ? TRUE : FALSE;

}



/**

* Test whether the fifo is empty

*

* @param ByteFifo*, The pointer to the ByteFifo

* @return bool, TRUE: empty, FALSE: not empty

*/

bool is_empty(ByteFifo* pFifo){

  return (pFifo->status & FIFO_IS_EMPTY) ? TRUE : FALSE;

}



/**

* Get a byte from byte fifo

* Return -1 if fifo is empty

*

* @param ByteFifo*, The pointer to the fifo

* @return int, the data. -1 means fifo is empty

*/

int get_byte(ByteFifo* pFifo){



  unsigned char _writps = pFifo->writps;

  unsigned char _readps = pFifo->readps;

  unsigned char _status = pFifo->status;



  if (_status & FIFO_IS_EMPTY) return -1;



  int b = *(pFifo->buffer+_readps);

  

  _readps++;

  _readps = (_readps >= pFifo->mxsize) ? 0 : _readps;



  if (_readps == _writps){

    _status |= FIFO_IS_EMPTY;

  }else{

    _status &= ~FIFO_IS_FULLY;

  }



  pFifo->readps = _readps;

  pFifo->status = _status;



  return b;

}



/**

* Put a byte to byte fifo

* Return -1 if fifo is fully

*

* @param ByteFifo*, The pointer to the fifo

* @param unsigned char, the byte need to put

* @return int, the byte had put into fifo, -1 means fifo is fully

*/

int put_byte(ByteFifo* pFifo, unsigned char b){



  unsigned char _writps = pFifo->writps;

  unsigned char _readps = pFifo->readps;

  unsigned char _status = pFifo->status;



  if (_status & FIFO_IS_FULLY) return -1;



  *(pFifo->buffer+_writps) = b;



  _writps++;

  _writps = (_writps >= pFifo->mxsize) ? 0 : _writps;

  

  if (_writps == _readps){

    _status |= FIFO_IS_FULLY;

  }else{

    _status &= ~FIFO_IS_EMPTY;

  }



  pFifo->writps = _writps;

  pFifo->status = _status;



  return (int) b;

}



INTERFACE void clear_fifo(ByteFifo* pFifo){

  pFifo->status = FIFO_IS_EMPTY;

  pFifo->writps = 0;

  pFifo->status = 0;

}



熟悉算法的人,可以看出这是一个通用字节循环队列的实现。这个队列的实现完全是可移植的,其实这些底层的结构性代码,我一般都是在PC上调试的,因为它们根本和单片机没有任何关系。



好了,到了这一步有了基础,看看如何在串口通信中使用这个FIFO,来做一个业务逻辑无关的通用串口程序,还是先看头文件uart.h(修改过,为方便理解去掉了多任务的同步机制),毕竟是体现设计思想的东西,哈哈



/**

* Copyright (c) 2006-2008 iWESUN Inf.

* All rights reserved.

*

* File: uart.h

* Author: Hu Dong  <hoodng@hotmail.com>

* Create: Jun 22, 2007

*/



#ifndef __UART_H__

#define __UART_H__



#include "bfifo.h"  // 看好,引入那个FIFO了



#define UART_TXBUF_SIZE 16  // 发送FIFO的大小

#define UART_RXBUF_SIZE 16  // 接收FIFO的大小



#define UART_RECVDATA 1

#define UART_SENDDATA 2

#define UART_RX_FULLY 4  // Buffer is fully

#define UART_TX_EMPTY 8  // Buffer is empty



#ifndef __ASSEMBLER__

/* These only work in C program */



/**

* Uart will callback this method when uart status had changed

*

* @param unsigned char, The status of transfer

*/

typedef void (*uart_hook)(unsigned char);  // CallBack,也就是钩子,比如可以用来干收到数据,或发送数据时闪闪灯啊什么的。



/* 什么什么控制块,受DOS时代东西的影响,哈哈*/

typedef struct UartControlBlock {

  __volatile__ unsigned char status;

  uart_hook hook;

  ByteFifo* txbuf;  // 定义发送FIFO

  ByteFifo* rxbuf;  // 定义接收FIFO

} UARTCB;



/**

* Initialize UART for Rx and Tx

* You should invoke this method to initializ UART

* Currently, this method just supported 8bit data, 1bit stop and none check

*

*/

INTERFACE void init_uart(uart_hook);



/**

* Put a char to UART Tx queue

*

* @param char, the char need put to UART

* @return 0 is successful, other values are failed

*/

INTERFACE int uart_putchar(char b);



/**

* Get a char from UART Rx queue

*

* @return the char, if equas to -1, there are some errors occur.

*/

INTERFACE int uart_getchar(void);



/*用来打印memory中的字符串,不是必须的,可以设计到别的地方*/

INTERFACE void uart_print_memstr(const unsigned char*);



/*用来打印FLASH中的字符串,不是必须的,可以设计到别的地方*/

INTERFACE void uart_print_pgmstr(const prog_uchar*);



/* 这一段宏定义,sbi, cbi都是宏定义,根据具体开发环境可以再定义

* 我在Mega系列gcc中的定义是:(定义在arch.h文件中)

*

* #define sbi(P, b) __asm__ __volatile__ ("sbi %0,%1" : :"I"(_SFR_IO_ADDR(P)), "I"(b))

* #define cbi(P, b) __asm__ __volatile__ ("cbi %0,%1" : :"I"(_SFR_IO_ADDR(P)), "I"(b))

*

* RS485_DDR,RS485_PORT, RS485_DEPIN, RS485_REPIN都定义在具体应用hardware.h中,

* 比如,我的一个具体应用中

* #define __RS485__ 1

* #define RS485_DDR DDRD

* #define RS485_PORT PORTD

* #define RS485_DEPIN PD2

* #define RS485_REPIN PD2

*/

#define enable_rs485_send()  sbi(RS485_PORT,RS485_DEPIN)

#define enable_rs485_recv()  cbi(RS485_PORT,RS485_REPIN)

#define disable_rs485_send() cbi(RS485_PORT,RS485_DEPIN)

#define disable_rs485_recv() sbi(RS485_PORT,RS485_REPIN)





#endif /* ! __ASSEMBLER__ */



#endif /* __UART_H__ */



很简单吧,看头文件还看不出我是要中断方式实现收发,还是查询方式。这就对了,底层实现是无所谓的,但头文件是很重要的。

又多说几句,我不知道大家在设计程序时,是不是也是先写头文件,反正我是这样的,有时候为了方法的名字和签名也要斟酌好半天,当然,还有注释,其实这就是我理解的设计。

有了uart.h,再来看uart.c吧,同样也是去掉了同步机制的代码。

大家都知道,中断方式更高级,毕竟少占用CPU时间,所以我的实现肯定是要用中断方式的。尤其是多任务系统,查询方式根本就是笨笨。



/**

* Copyright (c) 2006-2008 iWESUN Inf.

* All rights reserved.

*

* File: uart.c

* Author: Hu Dong  <hoodng@hotmail.com>

* Create: Jun 22, 2007

*/



#include "uart.h"



#if __UART__ == 1 // 有些系统不用串口通信,可以把代码屏蔽掉,以减少代码大小,我不知论坛上有多少人使用这种方法。



BYTEFIFO(rxbuf, UART_RXBUF_SIZE); // 创建接收FIFO的实例

BYTEFIFO(txbuf, UART_TXBUF_SIZE); // 创建发送FIFO的实例

UARTCB uart = { UART_TX_EMPTY, NULL, &txbuf, &rxbuf}; // 创建那个控制块



void _print(unsigned char);



/**

* Initialize UART for Rx and Tx

* You should invoke this method to initializ UART

* Currently, this method just supported 8bit data, 1bit stop and none check

*

*/

void init_uart(uart_hook hook){

  /* 这里又多说几句,看到好多人的hard code,很不舒服,要是时钟变了,波特率变了,

   * 怎么办?

   * 我还是隆重介绍我的方法,我通常在具体应用hardware.h里定义

   *

   * #ifndef F_CPU

   * #define F_CPU 8000000

   * #endif

   *

   * #define __UART__ 1

   * #define BAUDRATE 9600

   * #define UART_UBRR F_CPU/16/BAUDRATE-1   

   *

   * 以上的宏定义,在通常情况下(我还没有发现例外)是自适应你选定的时钟和波特率的

   */



  UBRRH = HI8(UART_UBRR);

  UBRRL = LO8(UART_UBRR);

  UCSRB = _BV(RXCIE) | _BV(TXCIE) | _BV(RXEN) | _BV(TXEN);

  UCSRC = 0x86; // Async, 8 bits data, 1 bit stop, None check



  uart.hook = hook;



  #if __RS485__ == 1

  RS485_DDR |= (_BV(RS485_DEPIN) | _BV(RS485_REPIN));

  disable_rs485_send();

  enable_rs485_recv();

  #endif

}



/**

* Put a char to UART Tx queue

*

* @param char, the char need put to UART

* @return 0 is successful, -1 is failed

*/

int uart_putchar(char b){

  int ret = 0;



  into_critical();  // 其实就是 cli

  

  /*

   * 我靠以下代码,来可能会引发发送中断

   */

  unsigned char status = UCSRA;

  if ( is_empty(uart.txbuf) && (status & _BV(UDRE))){

    // Fifo is empty and UDRE, so send byte directly

    UDR = b;

  }else{

    uart.status &= ~UART_TX_EMPTY;

    ret = put_byte(uart.txbuf, b); // 正在发送,多余的放到FIFO里,中断程序会自己取

  }



  exit_critical(); // 其实就是 sei



  return ret;

}



/**

* Get a char from UART Rx queue

*

* @return the char, if equas to -1, there are some errors occur.

*/

int uart_getchar(void){

  into_critical();



  int ret = get_byte(uart.rxbuf); // 接收更简单了,直接从FIFO读,读到-1没有数据

  uart.status &= ~(UART_RECVDATA | UART_RX_FULLY);



  exit_critical();



  return ret;

}



void uart_print_memstr(const unsigned char* p){

  #if __RS485__ == 1

  disable_rs485_recv();

  enable_rs485_send();

  #endif



  unsigned char b = *(p++);

  while(b != 0){

    _print(b);

    b = *(p++);

  }



  #if __RS485__ == 1

  _delay_ms(1);

  while(!(is_empty(&txbuf)))wdt_reset();

  disable_rs485_send();

  enable_rs485_recv();

  #endif

}



void uart_print_pgmstr(const prog_uchar* p){

  #if __RS485__ == 1

  disable_rs485_recv();

  enable_rs485_send();

  #endif



  unsigned char b = pgm_read_byte(p++);

  while(b != 0){

    _print(b);

    b = pgm_read_byte(p++);

  }



  #if __RS485__ == 1

  _delay_ms(1);

  while(!(is_empty(&txbuf)))wdt_reset();

  disable_rs485_send();

  enable_rs485_recv();

  #endif

}



void _print(unsigned char b){

  int err = uart_putchar(b);

  while(err == -1){

    wdt_reset();

    err = uart_putchar(b);

  }

}



/**

* Rx complete interrupt handler

*/

void NAKED SIG_UART_RECV(void);

void SIG_UART_RECV(void){

  into_critical();



  prologue(); // 可以理解成把所有寄存器保存起来

  

  if (!(uart.status & UART_RECVDATA)){

    uart.status |= UART_RECVDATA;

    if (uart.hook != NULL) uart.hook(uart.status); // 收到数据CallBack一下

  }

  

  unsigned char tmp = UCSRA;

  unsigned char b = UDR;

  if (!(tmp & (_BV(FE) | _BV(DOR)))){

    int err = put_byte(uart.rxbuf, b);  // 把收到的数据放到FIFO中

    if (err == -1){

      uart.status |= UART_RX_FULLY;

      if (uart.hook != NULL) uart.hook(uart.status); // FIFO满了,CallBack一下

    }

  }

  

  epilogue(); // 可以理解成恢复所有的寄存器,开中断

}



/**

* Tx data register empty interrupt handler

*/

void NAKED SIG_UART_TRANS(void);

void SIG_UART_TRANS(void){

  into_critical();



  prologue();

  

  int b = get_byte(uart.txbuf); // 发送寄存器空了,从FIFO中取下一个数据来发送

  if (b > 0){

    UDR = b;

    if (!(uart.status & UART_SENDDATA)){

      uart.status |= UART_SENDDATA;

      if (uart.hook != NULL) uart.hook(uart.status); // 发送数据,CallBack一下

    }

  }else{

    uart.status &= ~UART_SENDDATA;

    uart.status |= UART_TX_EMPTY;

    if (uart.hook != NULL) uart.hook(uart.status); // 没有数据了,CallBack一下

  }



  epilogue();

}



#endif



展示了4段代码,基本上和我这个AvrcX中的一样,这个串口通信也许在有些应用中并不适合,比如非要使用带地址位的桢结构(用于多机通信)等,但我觉得那些也不是必须的,我更倾向在高层协议里处理多机地址,那样其实更灵活。

以上的代码,基本上满足我的设计思想,具有容易移植,业务逻辑无关等特点。请大家拍砖。

出0入0汤圆

 楼主| 发表于 2007-7-3 01:07:41 | 显示全部楼层
代码放出来了,也有设计解析,请大家讨论讨论,看看有没有设计缺陷,算法bug等方面的问题,我倒是已经应用到一些项目里,目前还没有发现什么问题。但我觉得应该还是有挖掘和优化的余地。

所以觉得大家除了“顶”,还是尽可能多发表意见和建议,让我把代码优化到极致。

出0入0汤圆

发表于 2007-7-3 08:59:38 | 显示全部楼层
帮你顶一下,我还是不喜欢用print串口来调试程序,我觉得还是用仿真器设断点的方式直接快捷。至于设计缺陷,bug,光靠读程序来找我实在没这个耐心。头文件的重要性不用多说,但我一般还是先定义数据结构,然后一边写程序,一边想程序接口。主要是如果先把头文件写完,我觉得我的脑袋不太够用,呵呵。真的完全正确写完头文件,我认为这个程序就已经完成了至少80%,剩下的工作就成了体力劳动了。其实更好的方法是先写文档,包括功能设计、使用说明书、模块划分、程序接口设计、数据结构设计等等。等这些都写完了,项目就完成了一半,写程序占%10的时间,剩下的40%时间debug。

出0入0汤圆

发表于 2011-12-20 21:00:42 | 显示全部楼层
mark!!!!!!!!!!!!!!!!!!

出0入0汤圆

发表于 2011-12-20 21:36:05 | 显示全部楼层
这个号啊,等有时间再分析

出0入0汤圆

发表于 2012-1-8 12:58:47 | 显示全部楼层
楼主辛苦,学习了!
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-27 22:33

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表