导航:首页 > 操作系统 > 单片机结构体菜单

单片机结构体菜单

发布时间:2023-05-12 23:18:57

Ⅰ ARM单片机的头文件如何用结构体定义地

下面我们以ARM Cortex-M0内核单片机LPC1114的头文件lpc11xx.h文件进行说明。

1.先说两句

lpc11xx.h文件是lpc11xx系列单片机包含的头文件。这个文件的作用和51单片机中的reg51.h头文件是一个性质,都是用来定义寄存器在单片机中的地址的。

你现在就可以打开reg51.h文件和lpc11xx.h文件看看,对比后你会发现两个主要的区别,首先是lpc11xx.h文件的寄存器定义是用结构体的形式,而reg51.h文件中,寄存器的定义都是一条一条的很直接的地址定义。然后是reg51.h文件中有sfr这样的“伪c语言”,而lpc11xx.h中用的是标准的c语言。C语言的最大用武之地就是单片机,要想学c,就在单片机上学,要想学单片机,就先入门c语言。两者相辅相成的学,效果最好。学以致用,才是学习的最终目标。

2.lpc11xx.h文件中如何定义寄存器地址?

在文件中,定义寄存器地址用到了一下几方面的c语言基础知识:

结构体;

结构体指针;

宏定义#define

关键字typedef

关键字volatile

关键字const

lpc11xx.h文件中,把每个模块都定义了一个结构体,这些模块有SYSCON、IOCON、UART、GPIO、SSP、I2C、WDT、ADC等。

例如,下面是ADC模块的结构体定义:

typedef struct
{
__IO uint32_t CR;
__IO uint32_t GDR;
uint32_t RESERVED0;
__IO uint32_t INTEN;
__IO uint32_t DR[8];
__I uint32_t STAT;
} LPC_ADC_TypeDef;

结构体的定义有三种形式,我们这里使用的是“直接说明变量”的形式。

lpc11xx.h文件的第566~584行,给每个模块的结构体变量定义了结构体指针,并加了宏定义#define,为的是以后写程序时书写方便。

把鼠标放到uint32_t上面,单击鼠标右键,在弹出的菜单中选择“Go To Definition Of ‘uint32_t’”,如下图所示:

选择后,就会跳到它的定义之处,如下图所示:

typedef是类型重定义关键字,所以实际上,CR寄存器的定义是这样的:

__IO unsigned int CR;

按照同样的方法,可以找到__IO的定义为:

所以,CR寄存器定义实际上是:

volatile unsigned int CR;

volatile关键字的作用是为了让编译器不要优化这个变量。

unsigned int关键字,用来定义无符号的整形变量。

这时候,有人会问,为什么不直接写成这样呢?答:为了阅读方便。

__IO uint32_t CR;

看到这条语句,我们就会知道,CR寄存器是一个“32位的可读可写寄存器”。

volatile unsigned int CR;

同样的这句话,我们对它的了解就不是那么一目了然了。

3.如何查看每个寄存器的地址?

上面讲到,寄存器的地址是由结构体和结构体指针定义的。现在我们来验证一下它的正确性。

我们随便找个寄存器,比如ADC模块的INTEN寄存器(ADC中断允许寄存器),打开LPC1114的用户手册,找到第25章ADC模块部分,如下图所示:

从上面图中,可以看到INTEN的寄存器的地址是0x4001C00C,接下来,我们打开lpc11xx.c文件来验证一下吧。

打开lpc11xx.c文件,找到ADC模块的结构体,如下图所示:

然后再找到LPC_ADC_TypeDef的结构体指针,如下所示:

结构体指针就是用来指向一个地址的,我们来看看上面语句中的LPC_ADC_BASE是什么:

再看看上条语句中的LPC_APB0_BASE是什么:

现在终于挖到底了,原来LPC_ADC_TypeDef指针指向的地址为:

0x40000000+0x1C000=0x4001C000

c语言基础知识:结构体的第一个变量的地址=结构体指针的地址。

所以结构体的第一个变量地址就是0x4001C000,INTEN前面有3个4字节的变量,所以INTEN的地址就是0x4001C00C。

验证完毕。

4.程序中,如何操作寄存器?

C语言基础知识:用结构体变量指针访问结构体中的变量,形式有两种:

*结构体指针变量.变量名

结构体指针变量->变量名

还是拿INTEN寄存器为例,假设我们要给这个寄存器写0x837,可以这样写:

*LPC_ADC.INTEN=0x837;

LPC_ADC->INTEN=0X837;

以上两种形式,在写程序的时候,都可以用。人们习惯用第二种形式。

Ⅱ 单片机C语言中结构体的表达式

c语言不等号是用
!=,比如(a!=b)
另外根据实际使用情况,还可以用==判断,然后取反,(a!=b)
还可以写成(!(a==b))
再然后,c语言比较灵活的地方,(a-b)也可以用来判断两数是否相等(但不建议这样用)。这个实际上是判断(a-b)的结果是不是等于0,如果两数相等,结果等于0,表示“假”,如果不等,结果非0,表示真。

Ⅲ 单片机按键进行菜单选择的编程思想

有以下几种情况:
1.循环查询按键。当按键按第一次时间,进入第一层循环查询语句内部,执行恢复。不跳出该层循环,继续查询按键。当第二次按下时间,进入第二层循环查询语句内部,执行暂停。循环结束。若想反复暂停和恢复,就在外面再加一层while(1)类似的死循环,反复执行其内部的两层循环查询语句。
2.用一个标志变量,记住按键的状态。初始化为个值,如“暂停”,按键之后检查标志变量,是“暂停”就执行“恢复”,再让它变为“恢复”说明当前已经执行了恢复。反之亦然。
3.掉电暂停。这样需要按键能触发cpu工作。所以,需要按键接到外部中断上面。中断后可以恢复cpu工作。在中断中再判断是否要让cpu掉电与否。
不知道这种方法你能接受不?还是用外部中断。此按键触发中断后,关掉所有其他的中断,也即ea=0(最好先用个变量记住ea,方便恢复),然后就一直在中断中等待该按键第二次按下再恢复ea,最后退出中断。

Ⅳ 基于MSP430单片机的菜单程序设计思路,以及简单示例,最好C语言程序!

我以前倒是做过,不过程序还有点问题,调时间源誉耐的时候容易过界,但正常走时候就正常了。开发环境用的IAR,单片机用f149,显示用的1602的四线模式。
你自己看着改程序吧,其实我也是51上移植过去的。

悲剧了,帖不下了.我帖在我博客里了啊,自己去找吧.
主程序
__________________________分隔线____________________________________

#include <msp430x14x.h>
#include "ds1302.h"
#include "LCD1602x4_mps.h"

#define DS1302_SECOND 0x81 //时钟芯片的寄存器位置,存放时间
#define DS1302_MINUTE 0x83
#define DS1302_HOUR 0x85
#define DS1302_WEEK 0x8b
#define DS1302_DAY 0x87
#define DS1302_MONTH 0x89
#define DS1302_YEAR 0x8d

unsigned char DateString[11],TimeString[9],week_value[2],TempBuffer[7]; //
char hide_sec,hide_min,hide_hour,hide_day,hide_week,hide_month,hide_year;
char done,count,temp,flag,up_flag,down_flag;
//unsigned int temp_value=0,temp_max=0;temp_min=0; //温度值

void DateToStr(void) //将时间年,月,日,星期数据转换成液晶显示字符串,放到数组里DateString[]
{ unsigned char Year,Month,Day,Week;
Year=rtc_getyear();
Month=rtc_getmon();
Day=rtc_getdate();
Week=rtc_getday();

if(hide_year<2) //这里的if,else语句都是判断位闪烁,<2显示数据虚闹,>2就不显示,输出字符串为 2007/07/22
{
DateString[0] = '2';
DateString[1] = '0';
DateString[2] = Year/10 + '0';
DateString[3] = Year%10 + '0';
}
else
{
DateString[0] = ' ';
DateString[1] = ' ';
DateString[2] = ' ';
DateString[3] = ' ';
}
DateString[4] = '/';
if(hide_month<2)
{
DateString[5] = Month/10 + '0';
DateString[6] = Month%10 + '0';
}
else
{
DateString[5] = ' ';
DateString[6] = ' ';
}
DateString[7] = '/';
if(hide_day<2)
{
DateString[8] = Day/10 + '0';
DateString[9] = Day%10 + '0';
}
else
{
DateString[8] = ' ';
DateString[9] = ' ';
}
if(hide_week<2)
{
week_value[0] = Week%10 + '0'; //星期的数据另外放到 week_value[]数组里,跟年,月,日的分开存放,因为等一下要在最后显示
}
else
{
week_value[0] = ' ';
}
week_value[1] = '雹春\0';

DateString[10] = '\0'; //字符串末尾加 '\0' ,判断结束字符
}

void TimeToStr(void) //将时,分,秒数据转换成液晶显示字符放到数组 TimeString[];
{ unsigned char Hour,Minute,Second;
Hour=rtc_gethour();
Minute=rtc_getmin();
Second=rtc_getsec();
if(hide_hour<2)
{
TimeString[0] = Hour/10 + '0';
TimeString[1] = Hour%10 + '0';
}
else
{
TimeString[0] = ' ';
TimeString[1] = ' ';
}
TimeString[2] = ':';
if(hide_min<2)
{
TimeString[3] = Minute/10 + '0';
TimeString[4] = Minute%10 + '0';
}
else
{
TimeString[3] = ' ';
TimeString[4] = ' ';
}
TimeString[5] = ':';
if(hide_sec<2)
{
TimeString[6] = Second/10 + '0';
TimeString[7] = Second%10 + '0';
}
else
{
TimeString[6] = ' ';
TimeString[7] = ' ';
}
DateString[8] = '\0';
}

void show_time() //液晶显示程序
{
TimeToStr(); //时间数据转换液晶字符
DateToStr(); //日期数据转换液晶字符
// ReadTemp(); //开启温度采集程序
// temp_to_str(); //温度数据转换成液晶字符
LCD_PutStr(TempBuffer,25); //显示温度
LCD_PutStr(DateString,0); //显示日期
LCD_PutStr(week_value,15); //显示星期
LCD_PutStr(" Week",10); //在液晶上显示 字母 week
LCD_PutStr(TimeString,16); //显示时间
}
////////////////////////////////////////////////////////////////////////////

void outkey() //跳出调整模式,返回默认显示
{ unsigned char Second;
if (!(P1IN&BIT0))
{
count=0;
hide_sec=0,hide_min=0,hide_hour=0,hide_day=0,hide_week=0,hide_month=0,hide_year=0;
Second=dataread(DS1302_SECOND);
datawrite(0x8e,0x00); //写入允许
datawrite(0x80,Second&0x7f);
datawrite(0x8E,0x80); //禁止写入
done=0;//temp_max=0;sund=1;
while(!(P1IN&BIT0));
delay_nms(2);
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Upkey()//升序按键
{
if(!(P1IN&BIT1))
{
switch(count)
{case 1:
temp=dataread(DS1302_SECOND); //读取秒数
temp=temp+1; //秒数加1
up_flag=1; //数据调整后更新标志
if((temp&0x7f)>0x59) //超过59秒,清零
temp=0;
break;
case 2:
temp=dataread(DS1302_MINUTE); //读取分数
temp=temp+1; //分数加1
up_flag=1;
if(temp>0x59) //超过59分,清零
temp=0;
break;
case 3:
temp=dataread(DS1302_HOUR); //读取小时数
temp=temp+1; //小时数加1
up_flag=1;
if(temp>0x23) //超过23小时,清零
temp=0;
break;
case 4:
temp=dataread(DS1302_WEEK); //读取星期数
temp=temp+1; //星期数加1
up_flag=1;
if(temp>0x7)
temp=1;
break;
case 5:
temp=dataread(DS1302_DAY); //读取日数
temp=temp+1; //日数加1
up_flag=1;
if(temp>0x31)
temp=1;
break;
case 6:
temp=dataread(DS1302_MONTH); //读取月数
temp=temp+1; //月数加1
up_flag=1;
if(temp>0x12)
temp=1;
break;
case 7:
temp=dataread(DS1302_YEAR); //读取年数
temp=temp+1; //年数加1
up_flag=1;
if(temp>0x99)
temp=0;
break;
default:break;
}

while(!(P1IN&BIT1));
delay_nms(2);
}
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////
void Downkey()//降序按键
{
if(!(P1IN&BIT2))
{
switch(count)
{case 1:
temp=dataread(DS1302_SECOND); //读取秒数
temp=temp-1; //秒数减1
down_flag=1; //数据调整后更新标志
if((temp&0x7f)>0x59) //小于0秒,返回59秒
temp=0x59;
break;
case 2:
temp=dataread(DS1302_MINUTE); //读取分数
temp=temp-1; //分数减1
down_flag=1;
if(temp>0x59)
temp=0x59; //小于0秒,返回59秒
break;
case 3:
temp=dataread(DS1302_HOUR); //读取小时数
temp=temp-1; //小时数减1
down_flag=1;
if(temp==0x00)
temp=0x23;
break;
case 4:
temp=dataread(DS1302_WEEK); //读取星期数
temp=temp-1; //星期数减1
down_flag=1;
if(temp==0x00)
temp=0x07;
break;
case 5:
temp=dataread(DS1302_DAY); //读取日数
temp=temp-1; //日数减1
down_flag=1;
if(temp==0x00)
temp=0x31;
break;
case 6:
temp=dataread(DS1302_MONTH); //读取月数
temp=temp-1; //月数减1
down_flag=1;
if(temp==0x00)
temp=0x12;
break;
case 7:
temp=dataread(DS1302_YEAR); //读取年数
temp=temp-1; //年数减1
down_flag=1;
if(temp>0x99)
temp=0x99;
break;
default:break;
}

while(!(P1IN&BIT2));
delay_nms(2);
}
}

void Setkey()//模式选择按键
{
if(!(P1IN&BIT3))
{
count=count+1; //Setkey按一次,count就加1
done=1; //进入调整模式
while(!(P1IN&BIT3));
delay_nms(2);
}

}

void keydone()//按键功能执行
{ unsigned char Second;
if(flag==0) //关闭时钟,停止计时
{ datawrite(0x8e,0x00); //写入允许
temp=dataread(DS1302_SECOND);
datawrite(0x80,temp|0x80);
datawrite(0x8e,0x80); //禁止写入
flag=1;
}
Setkey(); //扫描模式切换按键
switch(count)
{
case 1:do //count=2,调整秒
{
outkey(); //扫描跳出按钮
Upkey(); //扫描加按钮
Downkey(); //扫描减按钮
if(up_flag==1||down_flag==1) //数据更新,重新写入新的数据
{
datawrite(0x8e,0x00); //写入允许
datawrite(0x80,temp|0x80); //写入新的秒数
datawrite(0x8e,0x80); //禁止写入
up_flag=0;
down_flag=0;
}

hide_sec++; //位闪计数
if(hide_sec>3)
hide_sec=0;
show_time(); //液晶显示数据
}while(count==2);break;
case 2:do //count=3,调整分
{
hide_sec=0;
outkey();
Upkey();
Downkey();
if(temp>0x60)
temp=0;
if(up_flag==1||down_flag==1)
{
datawrite(0x8e,0x00); //写入允许
datawrite(0x82,temp); //写入新的分数
datawrite(0x8e,0x80); //禁止写入
up_flag=0;
down_flag=0;
}
hide_min++;
if(hide_min>3)
hide_min=0;
show_time();
}while(count==3);break;
case 3:do //count=4,调整小时
{
hide_min=0;
outkey();
Upkey();
Downkey();
if(up_flag==1||down_flag==1)
{
datawrite(0x8e,0x00); //写入允许
datawrite(0x84,temp); //写入新的小时数
datawrite(0x8e,0x80); //禁止写入
up_flag=0;
down_flag=0;
}
hide_hour++;
if(hide_hour>3)
hide_hour=0;
show_time();
}while(count==4);break;
case 4:do //count=5,调整星期
{
hide_hour=0;
outkey();
Upkey();
Downkey();
if(up_flag==1||down_flag==1)
{
datawrite(0x8e,0x00); //写入允许
datawrite(0x8a,temp); //写入新的星期数
datawrite(0x8e,0x80); //禁止写入
up_flag=0;
down_flag=0;
}
hide_week++;
if(hide_week>3)
hide_week=0;
show_time();
}while(count==5);break;
case 5:do //count=6,调整日
{
hide_week=0;
outkey();
Upkey();
Downkey();
if(up_flag==1||down_flag==1)
{
datawrite(0x8e,0x00); //写入允许
datawrite(0x86,temp); //写入新的日数
datawrite(0x8e,0x80); //禁止写入
up_flag=0;
down_flag=0;
}
hide_day++;
if(hide_day>3)
hide_day=0;
show_time();
}while(count==6);break;
case 6:do //count=7,调整月
{
hide_day=0;
outkey();
Upkey();
Downkey();
if(up_flag==1||down_flag==1)
{
datawrite(0x8e,0x00); //写入允许
datawrite(0x88,temp); //写入新的月数
datawrite(0x8e,0x80); //禁止写入
up_flag=0;
down_flag=0;
}
hide_month++;
if(hide_month>3)
hide_month=0;
show_time();
}while(count==7);break;
case 7:do //count=8,调整年
{
hide_month=0;
outkey();
Upkey();
Downkey();
if(up_flag==1||down_flag==1)
{
datawrite(0x8e,0x00); //写入允许
datawrite(0x8c,temp); //写入新的年数
datawrite(0x8e,0x80); //禁止写入
up_flag=0;
down_flag=0;
}
hide_year++;
if(hide_year>3)
hide_year=0;
show_time();
}while(count==8);break;
case 8: count=0;hide_year=0; //count8, 跳出调整模式,返回默认显示状态
Second=dataread(0x80);
datawrite(0x8e,0x00); //写入允许
datawrite(0x80,Second&0x7f);
datawrite(0x8E,0x80); //禁止写入
done=0; //temp_max=0;sund=1;
break; //count=7,开启中断,标志位置0并退出
default:break;

}

}
////////////////////////////////////////////////////////////////////////////

void rtcinit ()
{
rtc_wp(0);
rtc_stop(0);
rtc_charger(1,1);
}

void sysinit ()
{ WDTCTL = WDTPW + WDTHOLD; //关闭看门狗
P4OUT = 0xff;
P4DIR = 0xff;
P5OUT = 0x0f;
P5DIR = 0xf0;
P6OUT = 0xfc;
P6DIR = 0xfc;
}

void main ()
{ unsigned char temp;
sysinit ();
rtcinit ();
LCD_init(); //液晶初始化
_EINT();
while (1)
{
while(done==1)
keydone(); //进入调整模式
while(done==0)
{
temp=rtc_getsec();
delay_nms(10);
if(temp!=rtc_getsec())
show_time(); //液晶显示数据
flag=0;
Setkey(); //扫描各功能键
}

}

}

Ⅳ 在单片机c语言中,结构体中的 U16 First_RF:1;是什么意思怎么解释 条件判断 if

U16 First_RF:1;是某个结构中定义了位域 First_RF,其宽度为1比特。

if (Flag.First_RF) 的意思是 如果 结构Flag的成员First_RF 非零。

Ⅵ 单片机菜单用结构体还是动态

单片机菜单最好是用动态,
这样可以实时用转,遇到问题也可以及时纠正。

Ⅶ 单片机数码管菜单怎样设计

数码管显示设计菜单只能用简单的数字或字母ABCDEF来表示,显示某一个数字或字母或其组合,按类似确定键后进入相应程序执行,这其实也不是很复杂的。比如最早我做的电脑刺绣机控制系统就只有数码管显示,有很多功能就依靠键盘和数码管的显示类容来与用户互动。

Ⅷ C51单片机语言枚举和结构体在单片机里面究竟用来处理什么功能

枚举和结构体的应用都差不多.
通常都是定义一个结构体或枚举,然后再用其定义成一个数组,
举例,有人做字库时有结构体,
里面包括一个unsigned int用于存汉字代码,
一个unsigned char[32]用于存点阵.
然后用该结构定义一个数组,
然后查询数组里unsigned int是否对应汉字,如果对应,则unsigned char[32]为该汉字的点阵,
这通常应用于LCD汉字显示.

总的一句话,就是方便数据归类,
如果学过C++,其实就有点类似C++的类,
当然,这比类要弱很多很多.

Ⅸ 单片机液晶翻页显示的程序

这个简单,你在当前菜单下设置一个下翻的按键,按一下时,重新写入后面的显示内容,也就是将前三行的内容删除掉,重新写入。
if(KEY_NEXT)
{
delate(page1);
write(page2);
}
void delate(unsigned char page)
{
...............
}
void write(unsigned char page)
{
...............
}

Ⅹ 用C语言写的多级菜单源程序(单片机),自己试验过,不要网上拷贝过来,谢谢。

程序中首先定义了一个结构体类型,他的名字叫做kbdtabstruct,然后用这个类型定义了一个数组,该数组的长度为size-of-keybd-menu
keytab[1]={1,7,2......}
1给了结构体成员 keystateindex,也就是keytab[1].keystateindex=1;
7给了keydnstate,也就是keytab[1].keydnstate=7;……依此类推。

阅读全文

与单片机结构体菜单相关的资料

热点内容
怎样制作贴天花板的解压球 浏览:337
服务器如何打开苹果 浏览:96
高响应比算法的实现 浏览:848
windows写命令行 浏览:61
腾讯天津数据中心服务器云空间 浏览:974
单片机扫描按键 浏览:386
如何设置google服务器 浏览:695
linuxtrace工具源码 浏览:178
源码第二次开发 浏览:784
如何获取网页php源码 浏览:729
还用飞那么源码 浏览:204
云服务器镜像可以随时更换吗 浏览:92
r600a压缩机多少钱 浏览:237
程序员那么可爱第几集在重庆相遇 浏览:674
上班两公里源码 浏览:817
南宁溯源码燕窝订制 浏览:933
在个人文件夹中新建文件 浏览:445
中国国家地理pdf下载 浏览:108
几套房子抵押可以解压其中一套吗 浏览:569
微爱app室外地板怎么装饰 浏览:231