嵌入式设计应用
例程的作用类似于函数,但含义更为丰富一些。例程是某个系统对外提供的功能接口或服务的集合。比如操作系统的API、服务等就是例程;Delphi或C++Builder提供的标准函数和库函数等也是例程。我们编写一个DLL的时候,里面的输出函数就是这个DLL的例程。
可以这么简单地来理解:把一段相对独立的代码写成单独的一个模块就是函数的概念。我们可以在自己的程序中编写很多个函数,从而实现模块化编程。但这些模块或者说函数并不一定向外输出(即提供给别的程序使用),只用于当前这个程序里面。此时这些函数就仅仅具有独立函数的意义,但不是例程。
main.c
#include 《htc.h》
__CONFIG(FOSC_HS & WDTE_OFF & LVP_OFF);
// int DATA[100][2]=0;
//用于存储采集过来的结果
long long int xishu1[16]={0,0,0,0}; //用于存储上位机发来的16个系数
bit FLAG_receivefactor=0; //接收标志位,如果为一表示本次中断需要接收系数
int Factor_number=-1;//系数编号,表示本次中断接收的是第几个编号的系数
long long int real=0;
/****************************************** 串口初始化函数
******************************************/
void USTRA_init()
{
BRG16=0;//使用8位波特率发生器
SPBRGL=12;//设置波特率发生寄存器的值4800
20SPBRGH=0;
ANSA1=0; //A1引脚被配置为端口或数字特殊功能
ANSA0=0;//A0引脚被配置为端口或数字特殊功能
RXDTSEL=1; //备用引脚控制寄存器0的bit7 即RA1上具有RX/DT功能
TXCKSEL=1; //备用引脚控制寄存器0的bit2 即RA0上具有TX/CK功能
TRISA0=0; //配置AO端口为输出
TRISA1=1; //配置A1端口为输入
SYNC=0; //EUSART选择异步模式工作
BRGH=0; //选择低频传送
TX9=0; //不发送第9位数据
RX9=0;//不接收第9位数据
TXEN=1; //串口发送功能打开
CREN=1; //串口接收功能打开
SPEN=1; //串口功能打开
TXIE=0; //关闭发送中断
RCIE=1;//打开接收中断
}
/*********************************************
AD转换初始化函数
功能:将AD模块初始化,本函数并未将AD模块初始化为测量压力还是温度模式,选择模式在ADModel_shift()函数中完成
*********************************************/
oid AD_init()
{
TRISC2=1; //配置RC2为输出模式
ANSC2=1; //配置RC2为模拟量模式
INLVLC2=0; //配置RC2为TTL输入方式
RC2=0;//配置RC2端口引脚电平小于VIL
ADCON1=0b10010000; //选择AD转换数据输出格式为右对齐,使用FOCS/8时钟作为AD转换时钟,选择负向参考电压为VSS,正向参考电压为VDD
ADIF=0; //清零AD转换中断
ADIE=0;//关闭AD转换中断
}
/************************************************
函数名称:ADModel_shift(int flag)
参数:标志量 int flag 0表示要将AD模块转换为测量压力模式,1表示转换为测量温度模式
功能:将AD模块在测量温度和压力之间进行切换
************************************************/
void ADModel_shift(int flag)
{
if(flag==0) {
ADCON0=0b00011001;
//打开通道6,并启用AD模块(本开发板用的是8号管脚,对应AD转换通道六)
}
else
{
ADCON0=0b01110101; //测温度并且使能AD模块
TSEN =1; //打开温度传感器功能
TSRNG=1; //温度传感器选择高电压模式
FVREN=1;//启用参考电压模块
}
// delay(1000);//模式转换完成后进行必要的延时等待,这样测量的结果才精准
}
/**********************************************
DA初始化
**********************************************/
void DA_init()
{
DACCON0=0b11100000;//打开DA模块,将DA转换的结果从DACOUT管脚输出,选择VDD提
供正向参考电压,选择VSS提供负向参考电压
RA0=0;//配置A0端口引脚电平小于VIL
// TRISA0=0;//在串口配置中本管脚已经配置为输出模式,这里可以省略
}
/***************************************************
简单的延时函数
参数:int time
****************************************************/
void delay(int time)
{
while(time--);
}
/****************************************************
程序总初始化函数
函数名:INIT()
返回值:无
功能:本函数实现对程序的总初始化,包括时钟的初始化,端口的设置,串口的初始化,A/D模块的初始化
*****************************************************/
void INIT()
{
/*时钟初始化*/
OSCCON=0b01101010;//初始化振荡器控制寄存器,选择主频4MHZ内部时钟
/*串口的初始化*/
USTRA_init();//执行串口初始化函数
/*AD模块的初始化*/
AD_init();
/*DA模块的初始化*/
// DA_init();//不能再串口使用时使用DA,因为2者公用同一个端口
/*中断的初始化*/
PEIE=1; //开启外设中断
GIE=1;//开启全局中断
}
/******************************************************
数据采集函数
函数名:Get_data()
返回值:无
功能:本函数实现一次性采集100组数据,将其存储在数组DATA[100][2]中,每组数据包含两个量:当前压力的数字量和当前温度的数字量
*******************************************************/
void Get_data()
{
int i=0;
ADModel_shift(0);//将AD模块调整为测量压力模式
delay(1000);
for(i=0;i《=9;i++)
{
ADGO=1;//开始AD转换
while(ADGO==1); //等待结果转换完成
DATA[i][0]=ADRESH;//将高8为结果存储在压力数据量低八位位置
delay(1000);//延时等待
DATA[i][0]=DATA[i][0]《《8; //将压力数据量的高八位左移8位
DATA[i][0]=ADRESL; //将低8位结果存储在压力数据量低八位位置
delay(1000);
ADIF=0;
//AD转换完成中断标志软件清零
}
ADModel_shift(1);//将AD模块调整为测量温度模式
delay(1000);
for(i=0;i《=9;i++)
{
ADGO=1;//开始AD转换
while(ADGO==1); //等待结果转换完成
DATA[i][1]=ADRESH;//将高8为结果存储在压力数据量低八位位置
delay(1000);//延时等待
DATA[i][1]=DATA[i][0]《《8; //将压力数据量的高八位左移8位
DATA[i][1]=ADRESL; //将低8位结果存储在压力数据量低八位位置
delay(1000);
ADIF=0;
//AD转换完成中断标志软件清零
}
}
/************************************* 串口发送函数
函数名:USTRA_Send()
参数:无
功能:本函数实现将AD转换完成的数据通过串口发送出去,函数执行一次,连发五个压力数据量再发五个温度数据量,开始发送时都发送一个0A01
*************************************/
void USTRA_Send()
{
int i =0;
TXREG=‘A’; //开始发送时先发送一个0A01 while(TRMT==0);
TXREG=‘1’;
while(TRMT==0);
ADModel_shift(0);//将AD模块调整为测量压力模式
delay(1000);
for(i=0;i《=4;i++)//连发五个压力数据量
{ ADGO=1;//开始AD转换
while(ADGO==1);//等待结果转换完成
TXREG=ADRESH;
while(TRMT==0); 10
TXREG=ADRESL;
while(TRMT==0);
ADIF=0;//AD转换完成中断标志软件清零
}
ADModel_shift(1);//将AD模块调整为测量温度模式
delay(1000);
for(i=0;i《=4;i++)//连发五个温度数据量
{
ADGO=1;//开始AD转换
while(ADGO==1);//等待结果转换完成
TXREG=ADRESH;
while(TRMT==0);
TXREG=ADRESL; 25
while(TRMT==0);
ADIF=0;//AD转换完成中断标志软件清零
}
}
/*****************************************
EEPROM写函数
******************************************/ 35
void EEPROM_write(int add,int data)
{
int k=0;
WREN=1;//打开写功能
EEADRL=add; //说明存储地址地址
EEDATL=data;//写1
EECON2=0x55;
EECON2=0xAA;
WR=1;
k=500;
while(k--);
WREN=0;//关闭写功能
}
/**********************************************
EEPROM读函数
***********************************************/
char EEPROM_Read(int add)
{ int k=0;
char a=0;
EEADRL=add;//说明存储地址
EEPGD=0;
CFGS=0;
RD=1;
k=500;
while(k--);
a=EEDATL;
return a;//返回读取的结果
}
/**********************************************
功能:串口接收中断服务函数
**********************************************/
interrupt ISR(void)
{
USTRA_init();
GIE=0;//关闭全局中断
char temp=0; //存放接收到的数据的缓存
int flag=0;
//表示本次接收到的数据是否为各个系数开头的标志量,1表示为标志量,0表示不为标志量,即数据,若为标志量,则表示上一个系数接收完毕,需要将其存储,否则则继续接收
int i=0,j=0; 30
if(FLAG_receivefactor==0)
//接收系数标志位,为1,表示本单片机已经被选中,并且被要求开始接收系数,为0表示本次单片机还未被选中
{
temp=RCREG; 35
if(temp==‘A’)
//若接收到的数据位A,表示要求本单片机发送采集的数据
USTRA_Send();
else if(temp==‘B’)
//若接收到的数据位B,表示上位机选中本单片机,要求接收系数
{
FLAG_receivefactor=1;
TXREG=‘N’;
}
}
else
//接收系数标志位,为1,表示本单片机已经被选中,被要求接收系数
{
temp=RCREG;
TXREG=temp;
while(TRMT==0);
switch(temp)
{
case ‘a’: Factor_number=0;
//表示下次发送的是系数1,系数1是第一个系数,所以没有前面的系数可以保存,所以Flag应该为1
flag=0;
break;
case ‘b’: Factor_number=1;
flag=1;
break;
case ‘c’: Factor_number=2;
flag=1;
break;
case ‘d’: Factor_number=3;
flag=1;
break;
case ‘e’: Factor_number=4;
flag=1;
break;
case ‘f’: Factor_number=5;
flag=1;
break;
case ‘g’: Factor_number=6;
flag=1;
break;
case ‘h’: Factor_number=7;
flag=1;
break;
case ‘i’: Factor_number=8;
flag=1;
break;
case ‘j’: Factor_number=9;
flag=1;
break;
case ‘k’: Factor_number=10;
flag=1;
break;
case ‘l’: Factor_number=11;
flag=1;
break;
case ‘m’: Factor_number=12;
flag=1;
break;
case ‘n’: Factor_number=13;
flag=1;
break;
case ‘o’: Factor_number=14;
flag=1;
break;
case ‘p’: Factor_number=15;
flag=1; break; case ‘q’: Factor_number=16;
flag=1;
break;
default:flag=0;
//该标志量表示本次接收中断传来的系数是否是标志量,0表示是数据,1表示就是标志量
}
if(flag==0&&temp!=‘a’)
//若此次中断未接收到标志量,或者接收到第一个系数的标志量即a,则不用将前面接收到的系数保存 10
{
real =real*10+(temp-48);
}
else
//若此次中断接收到标志量,则表示上一个系数传送完毕,对其进行存储 15
{
xishu1[Factor_number]=real;
//更新xishu1中相应系数的值
for(i=7,j=1;i》=0&&j《=8;i--,j++)
{
EEPROM_write((Factor_number-1)*8+j,real》》(8*i));
//将新的系数重新保存在EEPROM中,大端存储
TXREG=EEPROM_Read((Factor_number-1)*8+j);
while(TRMT==0);
}
real=0; //real清零
flag=0;//flag清零
if(Factor_number==16)
//如果最后一个系数接收完毕,则将FLAG_receivefactor标志量清零
{
FLAG_receivefactor=0;
}
}
}
GIE=1;//打开总中断
}
main()
{
int i=0,j=0;
long long int xishu2[4]={0};
long long long int result=0; long long int temp=0;
INIT();
for(i=0;i《=15;i++)
for(j=1;j《=8;j++)
{
xishu1[i]=EEPROM_Read((i*8)+j);//将系数从EEPROM中取出
TXREG=xishu1[i];
delay(1000);
if(j!=8)
xishu1[i]=xishu1[i]《《8;
}
TXREG=‘a’;
while(1)
{
int TEM=0,PRESS=0;
ADModel_shift(0);
//将AD模块调整为测量压力模式
delay(1000);
ADGO=1;//开始AD转换
while(ADGO==1);//等待结果转换完成
PRESS=ADRESH;
PRESS=TEM《《8; 20
// while(TRMT==0);
PRESS=PRESS+ADRESL;
//while(TRMT==0);
ADIF=0;//AD转换完成中断标志软件清零
ADModel_shift(1);//将AD模块调整为测量温度模式
delay(1000);
ADGO=1;//开始AD转换
while(ADGO==1);//等待结果转换完成
TEM=ADRESH; TEM=PRESS《《8;
//while(TRMT==0);
TEM=TEM+ADRESL;
// while(TRMT==0);
ADIF=0;//AD转换完成中断标志软件清零
}
TXREG=‘a’;//没法送完依次结果,就发送一个‘a’
while(TRMT==0);
}
}
全部0条评论
快来发表一下你的评论吧 !