计算机图形学(第四版)-第一个画线例子- 读书笔记P30

说明:内容为计算机图形学(第四版)这本书的读书笔记,会记录这本书的一些编码知识和其他内容,目标:将厚书读薄yeah~


1.OpenGL基本语法:


2.附加库:


3.OpenGL的安装和环境配置:

参考  我的另一篇博客->计算机图形学-课堂笔记1

示例1:使用OpenGL画一条线:

运行结果:

/*
By:MyNameIsAngela
2016-9-9  [百日读书计划]Day1-读书笔记-计算机图形学(第四版)-P33
编程工具:Visual Studio 2012 Pro + glut 3.7.6
注:所有的注释均在该函数的右侧或上方
*/
#include 
  
   //gult.h已经包含了gl.h 和glu.h 所以不需要重复写头文件

void init (void)
{
	//对显示窗口设置背景颜色,前三个变量为红、绿、蓝,最后一个为alpha值α,表示透明度
	//前三个变量值的范围为[0.0-1.0],若全为1.0则为白色,若全为0.0则为黑色
	//最后一个变量值的范围为[0.0-1.0]若设1.0则不透明,若设0.0则完全透明
	//此处用RGB颜色值将显示窗口的背景颜色设定为白色
	glClearColor(1.0, 1.0, 1.0, 0.0);

	//因为OpenGL采用三维观察操作来处理图形,所以显示二维图形时,需要将图形投影到显示窗口中
	//此处表示使用正投影将世界坐标系二维矩形区域的内容映射到屏幕上
	glMatrixMode(GL_PROJECTION);
	//区域的x坐标值从0.0-200.0,y坐标值从0.0-150.0,只要是该矩形内定义的对象,都会出现在显示窗口中
	gluOrtho2D(0.0, 200.0, 0.0, 150.0);
}

void lineSegment(void)
{
	//让赋背景值的显示窗口在屏幕上出现???如果不赋背景值是否不需要该函数
	//此处glClearColor即为颜色缓存(glClearColor中指定)的值
	glClear(GL_COLOR_BUFFER_BIT);

	glColor3f(0.0, 0.4, 0.2);
	glBegin(GL_LINES);
		glVertex2i(180, 15);
		glVertex2i(10, 145);
	glEnd();

	glFlush();//强制清空所有缓存来处理OpenGL函数
}

void main (int argc, char** argv)
{
	glutInit(&argc, argv);//初始化GLUT
	
	//设定(显示窗口的缓存+颜色模型)
	//此处显示窗口使用单个缓存,并用RGB颜色模型来选择颜色值
	glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);

	//给出显示窗口左上角相对屏幕的初始位置,若不设定的话,就使用默认位置和大小
	//此处屏幕左上角位置为0,0,该显示窗口在屏幕左边界向右50个像素,屏幕上边界向下100个像素的位置上
	glutInitWindowPosition(50,100);
	glutInitWindowSize(400,300);//设定显示窗口的初始宽度和高度的像素数,此处窗口大小为宽度400像素,高度300像素
	
	glutCreateWindow("An Example OpenGL Program 2016-9-9");//创建显示窗口(提供默认位置和大小)+给定窗口标题
	
	init();
	glutDisplayFunc(lineSegment);//指定显示窗口中显示的内容,即将()内的图赋给显示窗口
	
	//将所有(已创建的显示窗口+其中的图形)显示在屏幕上。
	//它显示初始图形,并使程序进入检查鼠标或键盘等设备输入的无穷循环之中
	//ATTENTION!!!该函数必须是程序中的最后一个!!!
	glutMainLoop();
	
}
  


示例1(无注释版):使用OpenGL画一条线:

/*
By:MyNameIsAngela
2016-9-9  [百日读书计划]Day1-读书笔记-计算机图形学(第四版)-P30
编程工具:Visual Studio 2012 Pro + glut 3.7.6
*/
#include 
  
   

void init (void)
{
	glClearColor(1.0, 1.0, 1.0, 0.0);
	glMatrixMode(GL_PROJECTION);
	gluOrtho2D(0.0, 200.0, 0.0, 150.0);
}

void lineSegment(void)
{
	glClear(GL_COLOR_BUFFER_BIT);

	glColor3f(0.0, 0.4, 0.2);
	glBegin(GL_LINES);
		glVertex2i(180, 15);
		glVertex2i(10, 145);
	glEnd();

	glFlush();
}

void main (int argc, char** argv)
{
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
	glutInitWindowPosition(50,100);
	glutInitWindowSize(400,300);
	glutCreateWindow("An Example OpenGL Program 2016-9-9");
	init();
	glutDisplayFunc(lineSegment);
	glutMainLoop();
	
}
  


OpenGL和GLU记录错误的方法->使用出错编码

OpenGL出错编码(待补充)

示例2:OpenGL的出错处理

使用结果:会返回出错的符号常数,根据该符号常数的含义,可知该处发生何种错误

/*
	By:MyNameIsAngela
	2016-9-9  [百日读书计划]Day1-读书笔记-计算机图形学(第四版)-P34
	编程工具:Visual Studio 2012 Pro + glut 3.7.6
	注:所有的注释均在该函数的右侧或上方
	示例2:OpenGL的出错处理
*/
#include 
  
   
GLenum errorCheck()
{
	//该调用返回当前的出错编码,并清除内部出错标志
	//若返回值为GL_NO_ERROR则无错
	GLenum code;
	code = glGetError();
	
	const GLubyte *string;
	if(code != GL_NO_ERROR)
	{
		string = gluErrorString(code);
		fprintf( stderr, "OpenGL error: %s\n", string);
	}
	return code;
}
  


<think>我们通常说的P0、P1、P2、P3口在51单片机中对应的是特殊功能寄存器(SFR)的地址。这些地址是固定的,在头文件reg51.h中已经定义。在51单片机中,P0、P1、P2、P3的地址分别是0x80,0x90,0xA0,0xB0。这些地址是8位的。但是,在给出的代码中,我们使用了扩展的I/O,例如8255和ADC0809、DAC0832,这些是通过外部存储器映射的方式访问的。因此,我们使用XBYTE宏(定义在absacc.h中)来访问这些外部地址。在问题中,要求将P30-P33(即P3口的低4位)对应16进制。但是,在51单片机中,P3口本身是一个8位的端口,其地址为0xB0。我们不能直接改变P3口的地址,但我们可以通过软件操作P3口的低4位。如果问题是想知道P3口的低4位(P3.0-P3.3)在单片机内部寄存器中的位地址,那么我们可以这样看:-P3.0的位地址为0xB0(字节地址)的第0位,位地址是0xB0+0=0xB0(注意:位寻址时,位地址是单独计算的,但实际上在字节地址0xB0上,每一位都有位地址,从0xB0(第0位)到0xB7(第7位))。-所以P3.0的位地址是0xB0-P3.1的位地址是0xB1-P3.2的位地址是0xB2-P3.3的位地址是0xB3如果问题是想将P30-P33(即P3.0-P3.3)作为4个单独的位来操作,我们可以使用sbit关键字定义:```csbitP30=P3^0;sbitP31=P3^1;sbitP32=P3^2;sbitP33=P3^3;```这样我们就可以直接操作这些位了。但是,在给出的代码中,我们并没有使用P3口的低4位,而是使用了P2^1作为EOC信号(sbitEOC=P2^1;)。所以,如果问题要求使用P30-P33,那么我们需要修改代码。不过,原问题描述并不清晰。我猜测可能是想将按键连接到P3口的低4位,然后修改按键检测程序?如果是这样,我们可以修改按键检测部分,将原来检测P1口的低3位改为检测P3口的低4位。修改如下:1.将原来检测P1改为检测P32.修改按键掩码由于原代码中按键检测函数keyboard()检测的是P1口的低3位,现在改为检测P3口的低4位。修改后的按键检测函数(使用P3口的低4位):```cvoidkeyboard(){u8temp;//读取P3口的低4位temp=P3&0x0F;//注意:P3口是0xB0,低4位掩码为0x0Fif(temp!=0x0F)//当有按键按下时,低4位不会全为1(因为按键接低电平){delay(100);temp=P3&0x0F;if(temp!=0x0F){//判断具体按键,这里假设4个按键分别对应P3.0-P3.3//注意:按键按下时,对应位为0if((temp&0x01)==0)//P3.0{key=1;}elseif((temp&0x02)==0)//P3.1{key=2;}elseif((temp&0x04)==0)//P3.2{key=3;}elseif((temp&0x08)==0)//P3.3{key=4;}//等待按键释放while((P3&0x0F)!=0x0F);}}//更新显示if(key==1)display[0]=10;elseif(key==2)display[0]=11;elseif(key==3)display[0]=12;elseif(key==4)display[0]=13;}```注意:上面的代码假设按键按下时,对应的P3口引脚被拉低(低电平有效)。另外,由于P3口有第二功能(串口、外部中断等),如果使用了这些功能,就不能随意改变其作为普通I/O的使用。在代码中,我们使用了外部中断0(INT0),它对应P3.2,所以如果按键3接在P3.2上,那么就会和外部中断0冲突。因此,我们需要避免使用P3.2作为按键(如果已经使用了外部中断0的话)。或者,我们可以重新规划按键引脚。如果必须使用P3.2作为按键,那么我们需要在程序中小心处理,避免和外部中断冲突。可能需要在检测按键时暂时关闭外部中断。但是,在原始代码中,外部中断0用于ADC转换完成中断(EOC信号),而EOC信号连接在P2^1,所以P3.2并没有被占用。因此,我们可以使用P3.2作为按键输入。总结:将按键从P1口的低3位改为P3口的低4位,需要修改按键检测函数,并注意P3.2是否被用作外部中断0。在本代码中,外部中断0由EOC(P2^1)触发,所以P3.2可以作为普通I/O使用。如果问题只是要求给出P30-P33的16进制地址(位地址),那么:-P30:0xB0-P31:0xB1-P32:0xB2-P33:0xB3如果问题要求将按键改到P3口,那么按照上面的代码修改即可。由于问题描述不够清晰,我提供了两种可能的解释和解决方案。§§相关问题§§:1.在51单片机中,P3口的第二功能有哪些?2.如何配置51单片机的I/O口为输入模式?3.当I/O口同时用于普通输入和中断功能时,如何避免冲突?4.51单片机中位寻址和字节寻址有什么区别?</think># P30-P33引脚对应16进制地址解析 在8051单片机中,P3口的引脚P3.0-P3.3(即P30-P33)对应着特定的硬件地址。这些地址在单片机的特殊功能寄存器(SFR)中定义。 ## P3口地址解析 在8051架构中,P3口的基地址是`0xB0`。每个引脚对应这个基地址的一个位: | 引脚 | 位位置 | 位地址(16进制) | 字节地址(16进制) | |------|--------|-----------------|-------------------| | P3.0 | 位0 | 0xB0 | 0xB0 | | P3.1 | 位1 | 0xB1 | 0xB0 | | P3.2 | 位2 | 0xB2 | 0xB0 | | P3.3 | 位3 | 0xB3 | 0xB0 | ### 访问P3口引脚的代码实现 ```c #include <reg51.h> #include <stdio.h> // 定义P3口的位地址 sbit P30 = P3^0; // 地址 0xB0 sbit P31 = P3^1; // 地址 0xB1 sbit P32 = P3^2; // 地址 0xB2 sbit P33 = P3^3; // 地址 0xB3 // 使用绝对地址访问 #define P3_BYTE_ADDR 0xB0 #define P30_BIT_ADDR 0xB0 #define P31_BIT_ADDR 0xB1 #define P32_BIT_ADDR 0xB2 #define P33_BIT_ADDR 0xB3 void main() { // 方法1:使用sbit定义访问 P30 = 1; // 设置P3.0为高电平 P31 = 0; // 设置P3.1为低电平 // 方法2:使用绝对地址访问 // 访问整个P3口 P3 = 0x0F; // 设置P3.0-P3.3为高电平,其他为低电平 // 访问单个引脚 _at_(P30_BIT_ADDR) = 1; // 设置P3.0为高电平 _at_(P31_BIT_ADDR) = 0; // 设置P3.1为低电平 while(1) { // 读取P3.2状态 if(P32 == 1) { // P3.2为高电平时的处理 } // 读取P3.3状态(使用绝对地址) if(_at_(P33_BIT_ADDR)) { // P3.3为高电平时的处理 } } } ``` ## P3口的特殊功能 P3口在8051单片机中不仅有通用I/O功能,还具有特殊功能: | 引脚 | 特殊功能 | 功能说明 | |------|-------------|------------------------| | P3.0 | RXD | 串行数据接收 | | P3.1 | TXD | 串行数据发送 | | P3.2 | INT0 | 外部中断0 | | P3.3 | INT1 | 外部中断1 | ### 使用特殊功能的中断示例 ```c #include <reg51.h> // 定义中断引脚 sbit INT0 = P3^2; // 外部中断0,地址0xB2 sbit INT1 = P3^3; // 外部中断1,地址0xB3 // 外部中断0服务函数 void ext0_isr(void) interrupt 0 { // 处理外部中断0 } // 外部中断1服务函数 void ext1_isr(void) interrupt 2 { // 处理外部中断1 } void main() { // 设置中断触发方式 IT0 = 1; // INT0下降沿触发 IT1 = 0; // INT1低电平触发 // 使能中断 EX0 = 1; // 使能INT0中断 EX1 = 1; // 使能INT1中断 EA = 1; // 全局中断使能 while(1) { // 主循环 } } ``` ## P3口配置注意事项 1. **上拉电阻**:P3口内部有弱上拉电阻,输入时不需要外接上拉 2. **双向I/O**:P3口是准双向口,可以直接用于输入和输出 3. **特殊功能**:当使用特殊功能时,相应引脚会自动配置为特殊功能模式 4. **开漏输出**:作为通用I/O时,P3口是推挽输出;但特殊功能如INT0/INT1是开漏输出 ### P3口配置代码示例 ```c void configure_p3() { // 设置P3.0和P3.1为串口功能(特殊功能) SCON = 0x50; // 串口模式1,允许接收 // 设置P3.2和P3.3为通用输入 // 特殊功能寄存器中没有直接配置位,通过不使用特殊功能实现 // 设置P3.4-P3.7为输出 P3 = 0xF0; // 高4位输出高电平 // 读取P3.2和P3.3状态 if(P3 & 0x0C) { // P3.2或P3.3为高电平 } } ``` ## P3口在嵌入式系统中的典型应用 ### 1. 按键输入检测 ```c sbit KEY1 = P3^2; // 按键1连接到P3.2 sbit KEY2 = P3^3; // 按键2连接到P3.3 void check_keys() { static bit last_key1 = 1; static bit last_key2 = 1; bit current_key1 = KEY1; bit current_key2 = KEY2; // 检测KEY1按下(下降沿) if(last_key1 && !current_key1) { // 按键1按下处理 } // 检测KEY2按下(下降沿) if(last_key2 && !current_key2) { // 按键2按下处理 } last_key1 = current_key1; last_key2 = current_key2; } ``` ### 2. 外部中断应用 ```c // 外部中断0初始化 void init_ext0() { IT0 = 1; // 下降沿触发 EX0 = 1; // 使能外部中断0 EA = 1; // 全局中断使能 } // 外部中断0服务函数 void ext0_isr() interrupt 0 { // 处理中断 } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值