最近在学ESAYARM1138,感觉比单片机要好用。做了个综合的小设计,在数码管上显示时间(由于找到的数码管是四位的,只能显示分和秒),用的是内部的16为定时器。在设计中开了个外部中断,用来切换时间的显示和温度的显示。
温度传感器用的是lm1138内部的温度传感器,
温度算法:
10位的ADC模块集成有一个温度传感器,可以用来获取芯片的当前温度。
在温度传感器特性图里,给出了以下公式:
Vsenso = 2.7 - (T + 55) / 75,单位:V
设Vsenso对应的ADC采样值为N,2.7V对应N1,(T+55)/75对应N2
已知:
N1 * (3 / 1024) = 2.7
N2 * (3 / 1024) = (T + 55) / 75
由此得到:
N = N1 - N2 = 2.7 / (3 / 1024) - ((T + 55)/75) / (3 / 1024)
解得:
T = (151040 - 225 * N) / 1024
结论:
ADC配置为温度传感器模式后,只要得到ADC采样值N,就能推算出当前的温度T。
主程序:
#include "systemInit.h"
#include <adc.h>
#include <stdio.h>
#include <timer.h>
// 定义LED
#define LED_PERIPH SYSCTL_PERIPH_GPIOG
#define LED_PORT GPIO_PORTG_BASE
#define LED_PIN GPIO_PIN_2
// 定义KEY1和KEY2
#define KEY1_PERIPH SYSCTL_PERIPH_GPIOD
#define KEY1_PORT GPIO_PORTD_BASE
#define KEY1_PIN GPIO_PIN_1
//#define KEY2_PERIPH SYSCTL_PERIPH_GPIOG
//#define KEY2_PORT GPIO_PORTG_BASE
//#define KEY2_PIN GPIO_PIN_5
// 定义ADC
#define ADCSequEnable ADCSequenceEnable
#define ADCSequDisable ADCSequenceDisable
#define ADCSequConfig ADCSequenceConfigure
#define ADCSequStepConfig ADCSequenceStepConfigure
#define ADCSequDataGet ADCSequenceDataGet
tBoolean ADC_EndFlag = false; // 定义ADC转换结束的标志
int min=0,sed=0,num=0,m=0;
int DATA_LED[10] =
{
//0~9的数码管段码
0xC0,//"0"
0xF9,//"1"
0xA4,//"2"
0xB0,//"3"
0x99,//"4"
0x92,//"5"
0x82,//"6"
0xF8,//"7"
0x80,//"8"
0x98,//"9"
};
// KEY1中断初始化
void key1IntInit(void)
{
SysCtlPeriEnable(KEY1_PERIPH); // 使能KEY1所在的GPIO端口
GPIOPinTypeIn(KEY1_PORT, KEY1_PIN); // 设置KEY1所在管脚为输出
GPIOIntTypeSet(KEY1_PORT, KEY1_PIN, GPIO_LOW_LEVEL); // 设置KEY1的中断类型
IntPrioritySet(INT_GPIOD, 1 << 5); // 设置KEY1中断优先级为1
GPIOPinIntEnable(KEY1_PORT, KEY1_PIN); // 使能KEY1所在管脚的中断
IntEnable(INT_GPIOD); // 使能GPIOD端口中断
}
/*
// KEY2中断初始化
void key2IntInit(void)
{
SysCtlPeriEnable(KEY2_PERIPH); // 使能KEY2所在的GPIO端口
GPIOPinTypeIn(KEY2_PORT, KEY2_PIN); // 设置KEY2所在管脚为输出
GPIOIntTypeSet(KEY2_PORT, KEY2_PIN, GPIO_LOW_LEVEL); // 设置KEY2的中断类型
IntPrioritySet(INT_GPIOG, 2<< 5); // 设置KEY2中断优先级为2
GPIOPinIntEnable(KEY2_PORT, KEY2_PIN); // 使能KEY2所在管脚的中断
IntEnable(INT_GPIOG); // 使能GPIOG端口中断
}
*/
void led() //数码管显示及数据处理程序
{
int T0,T1,T2,T3;
GPIOPinWrite(GPIO_PORTA_BASE, 0xFF, 0xFF);
T0=~DATA_LED[sed % 10];
GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_0, 0x00);
GPIOPinWrite(GPIO_PORTA_BASE, 0xFF, T0); //个位
SysCtlDelay(1* (TheSysClock / 6000)); // 延时约0.5ms
GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_0, 0xFF);
GPIOPinWrite(GPIO_PORTA_BASE, 0xFF, 0xFF);
T1=~DATA_LED[sed / 10 ];
GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_1, 0x00);
GPIOPinWrite(GPIO_PORTA_BASE, 0xFF,T1 );//十位
SysCtlDelay(1* (TheSysClock / 6000)); // 延时约0.5ms
GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_1, 0xFF);
GPIOPinWrite(GPIO_PORTA_BASE, 0xFF, 0xFF);
T2=~DATA_LED[min % 10];
GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_2, 0x00);
GPIOPinWrite(GPIO_PORTA_BASE, 0xFF,T2 );//百位
GPIOPinWrite(GPIO_PORTA_BASE, GPIO_PIN_7,0xff );//百位
SysCtlDelay(1* (TheSysClock / 6000)); // 延时约0.5ms
GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_2, 0xFF);
GPIOPinWrite(GPIO_PORTA_BASE, 0xFF, 0xFF);
T3=~DATA_LED[min / 10];
GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_3, 0x00);
GPIOPinWrite(GPIO_PORTA_BASE, 0xFF,T3 );//千位
SysCtlDelay(1* (TheSysClock / 6000)); // 延时约0.5ms
GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_3, 0xFF);
}
// ADC初始化
void adcInit(void)
{
SysCtlPeriEnable(SYSCTL_PERIPH_ADC); // 使能ADC模块
SysCtlADCSpeedSet(SYSCTL_ADCSPEED_125KSPS); // 设置ADC采样速率
ADCSequDisable(ADC_BASE, 3); // 配置前先禁止采样序列
// 采样序列配置:ADC基址,采样序列编号,触发事件,采样优先级
ADCSequConfig(ADC_BASE, 3, ADC_TRIGGER_PROCESSOR, 0);
// 采样步进设置:ADC基址,采样序列编号,步值,通道设置
ADCSequStepConfig(ADC_BASE, 3, 0, ADC_CTL_TS |
ADC_CTL_END |
ADC_CTL_IE);
ADCIntEnable(ADC_BASE, 3); // 使能ADC中断
IntEnable(INT_ADC3); // 使能ADC采样序列中断
IntMasterEnable(); // 使能处理器中断
ADCSequEnable(ADC_BASE, 3); // 使能采样序列
}
// ADC采样
unsigned long adcSample(void)
{
unsigned long ulValue;
ADCProcessorTrigger(ADC_BASE, 3); // 处理器触发采样序列
while (!ADC_EndFlag); // 等待采样结束
ADC_EndFlag = false; // 清除ADC采样结束标志
ADCSequDataGet(ADC_BASE, 3, &ulValue); // 读取ADC转换结果
return(ulValue);
}
// 计算芯片温度值
unsigned char tmpDisplay(unsigned long ulValue)
{
unsigned long T;
T= 151040UL - 225 * ulValue;
T=T/1024;
return(T);
}
//显示温度
void led2(int n) //数码管显示及数据处理程序
{
int T0,T1;
GPIOPinWrite(GPIO_PORTA_BASE, 0xFF, 0xFF);
T0=~DATA_LED[n % 10];
GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_0, 0x00);
GPIOPinWrite(GPIO_PORTA_BASE, 0xFF, T0); //个位
SysCtlDelay(1* (TheSysClock / 6000)); // 延时约0.5ms
GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_0, 0xFF);
GPIOPinWrite(GPIO_PORTA_BASE, 0xFF, 0xFF);
T1=~DATA_LED[n / 10 % 10];
GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_1, 0x00);
GPIOPinWrite(GPIO_PORTA_BASE, 0xFF,T1 );//十位
SysCtlDelay(1* (TheSysClock / 6000)); // 延时约0.5ms
GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_1, 0xFF);
GPIOPinWrite(GPIO_PORTA_BASE, 0xFF, 0xFF);
//T2=~DATA_LED[min % 10];
GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_2, 0x00);
GPIOPinWrite(GPIO_PORTA_BASE, 0xFF,0X00 );//百位
//GPIOPinWrite(GPIO_PORTA_BASE, GPIO_PIN_7,0xff );//百位
SysCtlDelay(1* (TheSysClock / 6000)); // 延时约0.5ms
GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_2, 0xFF);
GPIOPinWrite(GPIO_PORTA_BASE, 0xFF, 0xFF);
//T3=~DATA_LED[min / 10];
GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_3, 0x00);
GPIOPinWrite(GPIO_PORTA_BASE, 0xFF,0X00 );//千位
SysCtlDelay(1* (TheSysClock / 6000)); // 延时约0.5ms
GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_3, 0xFF);
}
// 主函数(程序入口)
int main(void)
{
jtagWait(); // 防止JTAG失效,重要!
clockInit(); // 时钟初始化:晶振,6MHz
adcInit();
unsigned long ulValue;
int t;
SysCtlPeriEnable(SYSCTL_PERIPH_GPIOA); // 使能LGPIO端口
SysCtlPeriEnable(SYSCTL_PERIPH_GPIOB);
GPIOPinTypeOut(GPIO_PORTA_BASE, 0xFF); // 设置管脚为输出
GPIOPinTypeOut(GPIO_PORTB_BASE, 0xFF);
// IntPriorityGroupingSet(0);
key1IntInit(); // KEY1中断初始化
//key2IntInit(); // KEY2中断初始化
SysCtlPeriEnable(SYSCTL_PERIPH_TIMER0); // 使能Timer模块
TimerConfigure(TIMER0_BASE, TIMER_CFG_16_BIT_PAIR | // 配置Timer为16位周期定时器
TIMER_CFG_A_PERIODIC);
TimerPrescaleSet(TIMER0_BASE, TIMER_A, 99); // 预先进行100分频
TimerLoadSet(TIMER0_BASE, TIMER_A, 60000); // 设置Timer初值,定时1s
TimerIntEnable(TIMER0_BASE, TIMER_TIMA_TIMEOUT); // 使能Timer超时中断
IntEnable(INT_TIMER0A); // 使能Timer中断
IntMasterEnable(); // 使能处理器中断
TimerEnable(TIMER0_BASE, TIMER_A); // 使能Timer计数
for (;;)
{
m=num%2;
if(m==0)
{
IntEnable(INT_TIMER0A);
TimerEnable(TIMER0_BASE, TIMER_A);
led();
}
if(m==1)
{
ulValue = adcSample(); // ADC温度采样
t= tmpDisplay(ulValue);
led2(t);
}
}
}
// 定时器的中断服务函数
void Timer0A_ISR(void)
{
unsigned long ulStatus;
ulStatus = TimerIntStatus(TIMER0_BASE, true); // 读取中断状态
TimerIntClear(TIMER0_BASE, ulStatus); // 清除中断状态,重要!
if (ulStatus & TIMER_TIMA_TIMEOUT) // 如果是Timer超时中断
{
if(sed==59)
{
if(min==59)
{
min=0;
}
else
min++;
sed=0;
}
else
sed++;
}
}
// GPIOD的中断服务函数
void GPIO_Port_D_ISR(void)
{
// unsigned char ucVal;
unsigned long ulStatus;
ulStatus = GPIOPinIntStatus(KEY1_PORT, true); // 读取中断状态
GPIOPinIntClear(KEY1_PORT, ulStatus); // 清除中断状态,重要
if (ulStatus & KEY1_PIN) // 如果KEY1的中断状态有效
{
num++; // 中断服务函数
/*
ucVal = GPIOPinRead(LED_PORT, LED_PIN); // 翻转LED
GPIOPinWrite(LED_PORT, LED_PIN, ~ucVal);
*/
SysCtlDelay(10 * (TheSysClock / 3000)); // 延时约10ms,消除按键抖动
while (GPIOPinRead(KEY1_PORT, KEY1_PIN) == 0x00); // 等待KEY抬起
SysCtlDelay(10 * (TheSysClock / 3000)); // 延时约10ms,消除松键抖动
}
}
/*
// GPIOG的中断服务函数
void GPIO_Port_G_ISR(void)
{
unsigned long ulStatus;
ulStatus = GPIOPinIntStatus(KEY2_PORT, true); // 读取中断状态
GPIOPinIntClear(KEY2_PORT, ulStatus); // 清除中断状态,重要
if (ulStatus & KEY2_PIN) // 如果KEY2的中断状态有效
{
if(sed==59) // 中断服务函数
{
if(min==59)
{
min=0;
}
else
min++;
sed=0;
}
else
sed++;
SysCtlDelay(10 * (TheSysClock / 3000)); // 延时约10ms,消除按键抖动
while (GPIOPinRead(KEY2_PORT, KEY2_PIN) == 0x00); // 等待KEY抬起
SysCtlDelay(10 * (TheSysClock / 3000)); // 延时约10ms,消除松键抖动
}
}
*/
// ADC采样序列3的中断
void ADC_Sequence_3_ISR(void)
{
unsigned long ulStatus;
ulStatus = ADCIntStatus(ADC_BASE, 3, true); // 读取中断状态
ADCIntClear(ADC_BASE, 3); // 清除中断状态,重要
if (ulStatus != 0) // 如果中断状态有效
{
ADC_EndFlag = true; // 置位ADC采样结束标志
}
}
注:程序是我的原创,数码管部分用了两个显示函数主要是为了显示效果。上面的程序只是主程序,使用时只需要添加在工程模版中就可以了,不过要在工程模版中加入相应必要的文件。另外,在启动代码处要打开相应的中断(在工程模版中不会打开全部的中断,自己根据需要设置,这是我学习中发现的),否则程序无法实现其功能。