您的位置:首页 > 其它

4、利用Rc震荡电路,脉冲计数,测量外部温度 细节的一些思考。

2012-10-10 16:19 417 查看
前一段时间,有人问我怎么用单片机的io口加上一些简单的外部电路测量外部温度。我当时是莫名其妙,我承认我从来没有想过这个问题。所以当时我很肯定的回答不可能。(在我的印象中,测温一般用温度传感器,或者热敏电阻之类的。怎么也要用个ad转换器吧。)

在坐公交车回去的路上,我仔细想了这个问题。单片机的io口能直接测到的只有电压,只能分辨高低电平嘛。单片机要想直接测温,只能是测外部脉冲的频率,然后再做映射(嘿嘿,其实我…..)。不管是利用温度传感器还是热敏电阻测温,其原理都是把一些参数的变化映射到温度。一个意思哦。

还好我的电子电路不是很差,还晓得Rc震荡电路可以产生脉冲。而且它的频率和电阻以及电容有关系,是个确定表达式,具体是什么忘记了。

这里只做软件的处理,电路嘛,以后再补上。哈哈

脉冲、温度映射包如下

/*

* package that pulse to temperture

*

*/

struct pulse_tem{

unsigned int pulse;

float temp_value ;

};

这个映射数据包是自己经过试验得出来的。可以这样初始化:

struct pulse_tem map_data[]={

{100, 35},

{110, 35.5},

(120, 36),

{125, 26.5},

......

{200, 45 }

}

数据随便加咯。。不过有一点要特别注意,数据要从小到大排列。因为后面使用了二分搜索算法。 多点准确些,而且也不会对性能造成影响。长度也可以很容易计算出来。

map_data_len = sizeof(map_data) / sizeof(map_data[0]) ;

把测温问题转换成脉冲温度映射问题后,思路就很清晰了。无非就是两个步骤:数据的获得与数据的处理。

1、
数据的获得。

为了简单些,就用单片机意思意思哈。只需要使用单片机的一个外部中断,和一个定时器。(定时器有计数功能,不过这里貌似没有作用。因为算的是频率)。先定义外部中断为高优先级中断。

这里定义几个宏:

#define external_interrupt_enable( ) ………

#define external_interrupt_disable( ) ………

设置为边沿触发。

#define timer_interrupt_enable( ) …………

#define timer_interrupt_disable( ) …………

#define pulse_temp_conversion_start( ) { timer_interrupt_enable( ) ; external_ interrupt_enable( ) }

定义两个个全局变量 volatile unsigned int pulse_count; volatile float tem_value; (当然了,最好定义成全局静态变量。)

注意: #define timer_interrupt_enable( ) ………… 应该把重置定时器初值,以及清零pulse_count


定时器中断响应函数如下:

_irq_timer_intrrupt_handle(void)

{

int id;

external_interrupt_disable( ) ;

timer_interrupt_disable( ) ;

id = mybinsearch(&pulse_coun, map_data, size_t sizeof(struct pulse_tem), size_t map_data_len, mycmp_s); // this function is written by ourself like system provide .

if(id == 0 || id == (map_data_len - 1) )

tem_value = map_data[id].temp_value; // obtain temperature directly

if(id > 0 && id < (map_data_len - 1))

tem_value = ( map_data[id].temp_value + map_data[id - 1].temp_value ) / 2.0 ; // obtain temperature in average.

}

注:中断里做了浮点数运算,嘿嘿。

外部中断响应函数如下:

_irp external_ interrupt_handle(void)

{

pulse_count++ ;

}

这种是最简单的数据获得了,没有做数据缓存。 使用的时候需要注意.。后面有一个做数据缓存的方法,不过代码增加了不少。

下面是一个改写了的二分搜索算法,它和系统提供的binsearch有一点点的不同。

1、
它返回的是一个索引号,而系统返回的是一个指向空类型的指针,个人习惯问题。

2、
由于特殊需求,这里返回的是第一个比它大或相等的对象的索引号。如果不在范围内,则返回-1.

int mybinsearch(void *key, void *base, size_t width, size_t size, int (*cmp)(void *a, void *b))

{

int left,right,mid;

char *pbase =(char *)base

left = 0;

right = size -1;

if(cmp(pbase, key) < 0 || cmp(pbase + right*width, key) < 0)

return -1 ;

while(left <= right)

{

mid = left + (right-left)/2;

if( cmp(pbase + mid * width, key) >= 0 )

right = mid-1;

else if(cmp(pbase + mid * width, key) < 0 )

left = mid+1;

}

return (left + 1 );

}

提供的cmp函数如下:

int mycmp_s(void *a, void *b)

{

return ((struct pulse_tem *)a)->pulse - *(unsigned int *)b ;

}

注意:我开始是写成return (struct pulse_tem *)a ->pulse - *(unsigned int *)b ;他娘的老是提示出错,找了好久,在印象中()的优先级比->高呀。。妈呀,书上的东西不能全信呢,害死人。

提供的函数写完了。至于操作嘛,嘿嘿。

需要测温度的时候:

pulse_temp_conversion_start( );

至于温度的提取嘛,直接取咯,。还能咋样啊。读tem_value就可以了。

上面的方法比较直接,不过它有一个缺陷。只能读到某个时间的温度,不能读到一个时间段的温度。 就是没有做数据缓存啦。
数据缓存可以用循环栈或者循环队列来搞定。

先声明一个温度获得数据包:

struct temperature_data {

float temperature ;

char msg[4]; // reserve .

};

typedef struct q_msg { /* QUEUE CONTROL BLOCK */

struct temperature_data *QStart; /* Pointer to start of queue data */

struct temperature_data *QEnd; /* Pointer to end of queue data */

struct temperature_data *QIn; /* Pointer to where next message will be inserted in the q*/

struct temperature_data *QOut; /* Pointer to where next message will be extracted from the*/

unsigned short QSize; /* Size of queue (maximum number of entries) */

unsigned short QEntries; /* Current number of entries in the queue */

} Q_MSG;

操作就是初始化,入队,出队咯。。把入队或者出队稍微改一下就变成栈了。嘿嘿

Q_MSG *queue_init(Q_MSG *pq, struct temperature_data *start, size_t size)

{

pq->QStart = start; /* Initialize the queue */

pq->QEnd = &start[size];

pq->QIn = start;

pq->QOut = start;

pq->QSize = size;

pq->QEntries = 0;

return pq ;

}

bool queue_in(Q_MSG *pq, struct temperature_data msg)

{

if (pq->QEntries >= pq->QSize)

return false;

*pq->QIn++ = msg; /* Insert message into queue */

pq->QEntries++; /* Update the nbr of entries in the queue*/

if (pq->QIn == pq->QEnd)

{ /* Wrap IN ptr if we are at end of queue */

pq->QIn = pq->QStart;

}

return true ;

}

struct temperature_data *queue_out(Q_MSG *pq)

{

struct temperature_data *msg ;

if (pq->QEntries > 0)

{ /* See if any messages in the queue */

msg = pq->QOut++;

/* Yes, extract oldest message from the queue */

pq->QEntries--;

/* Update the number of entries in the queue */

if (pq->QOut == pq->QEnd)

{ /* Wrap OUT pointer if we are at the end of the queue */

pq->QOut = pq->QStart;

}

return (msg);

}

return (NULL) ;

}

/*

* *the message is posted at the front instead of the end of the queue.

* *like stack to use.

* */

bool queue_in_front(Q_MSG *pq, struct temperature_data msg)

{

if (pq->QOut == pq->QStart)

{ /* Wrap OUT ptr if we are at the 1st queue entry */

pq->QOut = pq->QEnd;

}

pq->QOut--;

*pq->QOut = msg; /* Insert message into queue */

pq->QEntries++;

return true ;

}

代码一大堆,怎么用到上面的程序中去呢?还需要做一些工作啦。

定义一个队列直接用的数组,全局变量:

struct temperature_data temperature_data_queue[10] ;

定义一个 队列以及一个指向队列的指针,都是全局变量:

Q_MSG q_msg, *pq_msg = &q_msg ;

定时器中断函数如下:

_irq timer_intrrupt_handle(void)

{

int id;

struct temperature_data temp_data;

external_interrupt_disable( ) ;

timer_interrupt_disable( ) ;

id = mybinsearch(&pulse_count, map_data, sizeof(struct pulse_tem), map_data_len, mycmp_s); // this function is written by ourself like system provide .

if(id == 0 || id == (map_data_len - 1) )

tem_value = map_data[id].temp_value; /* obtain temperature directly */

if(id > 0 && id < (map_data_len - 1))

tem_value = ( map_data[id].temp_value + map_data[id - 1].temp_value ) / 2.0 ; /* obtain temperature in average. */

memset(&temp_data, 0, sizeof(struct temperature_data));

temp_data.temperature = tem_value ;

queue_in(pq_msg, temp_data);

}

队列初始化函数的使用:

queue_init(pq_msg, temperature_data_queue , sizeof(temperature_data_queue) / sizeof(temperature_data_queue[0])) ;

温度数据的获得:

temperature = (queue_out(pq_msg)) -> temperature;

我靠!,头都晕了。搞什么咯。。。娘的!。。问题不少啊,还得好好瞧瞧。。花一些时间做测试。中断里直接做了浮点数运算,偷懒啦。

。。。没有直接做测试,也不知道对不对。帮忙看看哈。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: