买了一块mega16的学习板,一直放着,今天心血来潮,做了一个小实验。利用单片机自带的AD进行电压采集,再通过串口USART将采集到的数据传输至PC机,上位机程序采用Labview对串口进行编程,读取单片机送过来的字节数据,电压换算在上位机中进行。
单片机A/D部分较为简单,只要按照使用手册进行编程就可以了,这里读取数据时没有采用中断,而是采用查询方式,个人觉得查询方式更为常用,将AD部分做一个子程序后,在需要的时候进行调用,十分方便,但是考虑到程序执行时间,采样频率不宜太高。A/D程序如下
#include <mega16.h>
#include <delay.h>
#define uchar unsigned char
#define uint unsigned int
void Init_ADC(void)
{
ADMUX=0x40;
ADCSRA=0x87;
}
uint ADC(void)
{
uint AD_value=0;
uint temp;
ADCSRA=ADCSRA|(1<<6);//启动一次AD转化
while(!(ADCSRA&(1<<4)));
ADCSRA|=1<<4;
temp=ADCL; //先读取低字节
AD_value=ADCH; //再读取高字节
AD_value=(AD_value<<8)|temp;
return AD_value;
}
通信部分只要对USART进行编程,如果采用CVAVR,它的函数库里自带有char getchar(void)和void putchar(char c)(
Standard C Input/Output Functions )两个函数,其实这两个函数就是串口的驱动函数,如果不想自己变成,那么就用这两个函数吧,不过在用他们之前同样需要对串口进行必要的设置,如波特率、数据位数等。这里自己编写了串口输入输出函数。
void Put_usart(uchar data)
{
while(!UCSRA.5);
UCSRA=UCSRA|0x40; //TCX清零
UDR=data;
}
uchar Get_usart(void)
{
while(!UCSRA.7); //等待RXT为1
return UDR;
}
实际上,在主程序中,因为串口的数据接收是随机的,不知道上位机什么时候发数据过来,就是说单片机没有主动权,所以数据接收最好采用中断,从而避免循环查询的麻烦。中断函数如下
interrupt [USART_RXC] void USART_RXC_isr(void) //USART接收中断
{
getdata=UDR;
Data_to_disbuf(getdata);
}
主程序就是每隔500ms进行一次数据采集并把采集到的数据发送至上位机
#include <mega16.h>
#include <header.h>
#include <stdio.h>
bit time_500ms_ok;
bit time_4ms_ok;
uchar time_counter;
uchar posit=0;
uchar getdata=0;
uchar dis_buff[4];
#define OE_138 PORTA.4
flash uchar Ledcode[29]={0x03,0x9f,0x25,0x0d,0x99,0x49,0x41,0x1f,
0x01,0x09};
flash uchar Bitcode[8]={0xe0,0x60,0xa0,0x20,0xc0,0x40,0x80,0x00};
void Data_to_disbuf(uint data)
{
uchar i;
for(i=0;i<4;i++)
{
dis_buff[3-i]=data%10;
data=data/10;
}
}
void Display(void)
{
OE_138=0;
Send_74HC595(Ledcode[dis_buff[posit]]);
PORTA=(PORTA&0x1f)|Bitcode[posit];
OE_138=1;
if(++posit>3)
posit=0;
}
void main(void)
{
uint AD_data;
uchar AD_H,AD_L;
TCCR0=0x0c; //CTC模式 256分频 16000000/256*1000=0.016ms
TCNT0=0x00;
OCR0=0x7c; //中断一次2ms 124+1=125*0.016=2
TIMSK=0x02; //允许time0匹配中断
DDRA=0xfe;
Init_ADC();
Init_usart();
#asm("sei")
while(1)
{
if(time_4ms_ok)
{
time_4ms_ok=0;
//data=Get_usart();
Display();
}
if(time_500ms_ok)
{
time_500ms_ok=0;
AD_data=ADC();
AD_H=AD_data>>8;
AD_L=AD_data&0x00ff;
Put_usart(AD_H);
Put_usart(AD_L);
//Data_to_disbuf(AD_data);
}
}
}
interrupt [TIM0_COMP] void time0_comp_isr(void) //定时器中断
{
time_counter++;
if(time_counter%2==0)
time_4ms_ok=1;
if(time_counter>=250)
{
time_counter=0;
time_500ms_ok=1;
}
}
interrupt [USART_RXC] void USART_RXC_isr(void) //USART接收中断
{
getdata=UDR;
Data_to_disbuf(getdata);
}
另一个大的方面就是上位机编程了,我只会使用Labview,幸好LV对串口进行编程还是很简单的,就不多说了,附代码先。 |