Memory Addressing

本文详细介绍了计算机内存管理中的页表机制,包括页全局目录、页中间目录及页表等概念,并解释了线性地址如何被划分为四部分来映射到实际的物理内存地址。同时,文中还探讨了用户态和内核态下线性地址空间的划分。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

The Page Global Directory includes the addresses of several Page Middle Directories, which in turn include the addresses of several Page Tables. Each Page Table entry points to a page frame. The linear address is thus split into four parts. The figure does not show the bit numbers because the size of each part depends on the computer architecture.

 

/* PAGE_SHIFT determines the page size */

#define PAGE_SHIFT      12

#define PAGE_SIZE      (1UL << PAGE_SHIFT)

#define PAGE_MASK      (~(PAGE_SIZE-1)

 

/*

 * PMD_SHIFT determines the size of the area a second-level page table can map

 */

#define PMD_SHIFT      20

#define PMD_SIZE       (1UL << PMD_SHIFT)

#define PMD_MASK       (~(PMD_SIZE-1))

 

/*

 * PGDIR_SHIFTdetermines what a third-level page table entry can map

 */

#define PGDIR_SHIFT    20

#define PGDIR_SIZE     (1UL << PGDIR_SHIFT)

#define PGDIR_MASK     (~(PGDIR_SIZE-1))

 

/*

 * entries per pagedirectory level: the sa110 is two-level, so

 * we don't reallyhave any PMD directory physically.

 */

#define PTRS_PER_PTE   256

#define PTRS_PER_PMD   1

#define PTRS_PER_PGD   4096

#define USER_PTRS_PER_PGD  (TASK_SIZE/PGDIR_SIZE)

Thelinear address space of a process is divided into two parts:

• Linear addresses from 0x00000000 to PAGE_OFFSET -1 can be addressedwhen the processis in either User or Kernel Mode.

• Linear addresses from PAGE_OFFSET to 0xffffffff can be addressed onlywhen the processis in Kernel Mode.

Usually,the PAGE_OFFSET macro yields the value 0xc0000000: this means that the fourth giga byte of linear addresses is reserved for the kernel, while the first three giga bytes are accessible from both the kernel and the user programs. However, the value of PAGE_OFFSET maybe customized by the user when the Linux kernel image is compiled.

IIC.c #include "IIC.h" #include "font.h" //IIC延时函数 void IIC_delayus(unsigned int i) { unsigned int j,k; for(k=0;k<i;k++) for(j=0;j<4;j++); } //IIC初始化函数 void IIC_ioinit() { P6DIR |= BIT1 | BIT5; // 配置为输出 P6OUT &= ~(BIT1 | BIT5); // 初始低电平 P6REN |= BIT1 | BIT5; // 启用内部上拉 } //开始一个IIC通信 void IIC_start() { SCL_HIGH; SDA_HIGH; //IIC_delayus(2); SDA_LOW; //IIC_delayus(2); SCL_LOW; } //停止IIC通信 void IIC_stop() { SCL_LOW; SDA_LOW; //IIC_delayus(2); SCL_HIGH; SDA_HIGH; //IIC_delayus(2); } //IIC发送一个byte void IIC_writebyte(unsigned char IIC_byte) { unsigned char i; for(i=0;i<8;i++) { if(IIC_byte&0x80) SDA_HIGH; else SDA_LOW; SCL_HIGH; SCL_LOW; IIC_byte<<=1; //loop } SDA_HIGH; SCL_HIGH; SCL_LOW; } void IIC_writecmd(unsigned char IIC_command) { IIC_start(); IIC_writebyte(0x78); //Slave address,SA0=0 IIC_writebyte(0x00); //write command IIC_writebyte(IIC_command); IIC_stop(); } void IIC_writedata(unsigned char IIC_data) { IIC_start(); IIC_writebyte(0x78); IIC_writebyte(0x40); //write data IIC_writebyte(IIC_data); IIC_stop(); } /**************************LCD 设置坐标*******************************/ void LCD_Set_Pos(unsigned char x, unsigned char y) { IIC_writecmd(0xb0+y); IIC_writecmd(((x&0xf0)>>4)|0x10); IIC_writecmd((x&0x0f)|0x01); } /***************************LCD复位************************************/ void LCD_CLS(void) { unsigned char y,x; for(y=0;y<8;y++) { IIC_writecmd(0xb0+y); IIC_writecmd(0x01); IIC_writecmd(0x10); for(x=0;x<X_WIDTH;x++) IIC_writedata(0); } } /***************************LCD初始化************************************/ void LCD_Init(void) { IIC_ioinit(); IIC_writecmd(0xAE); //display off IIC_writecmd(0x20); //Set Memory Addressing Mode IIC_writecmd(0x10); //00,Horizontal Addressing Mode;01,Vertical Addressing Mode;10,Page Addressing Mode (RESET);11,Invalid IIC_writecmd(0xb0); //Set Page Start Address for Page Addressing Mode,0-7 IIC_writecmd(0xc8); //Set COM Output Scan Direction IIC_writecmd(0x00);//---set low column address IIC_writecmd(0x10);//---set high column address IIC_writecmd(0x40);//--set start line address IIC_writecmd(0x81);//--set contrast control register IIC_writecmd(0x7f); IIC_writecmd(0xa1);//--set segment re-map 0 to 127 IIC_writecmd(0xa6);//--set normal display IIC_writecmd(0xa8);//--set multiplex ratio(1 to 64) IIC_writecmd(0x3F);// IIC_writecmd(0xa4);//0xa4,Output follows RAM content;0xa5,Output ignores RAM content IIC_writecmd(0xd3);//-set display offset IIC_writecmd(0x00);//-not offset IIC_writecmd(0xd5);//--set display clock divide ratio/oscillator frequency IIC_writecmd(0xf0);//--set divide ratio IIC_writecmd(0xd9);//--set pre-charge period IIC_writecmd(0x22); // IIC_writecmd(0xda);//--set com pins hardware configuration IIC_writecmd(0x12); IIC_writecmd(0xdb);//--set vcomh IIC_writecmd(0x20);//0x20,0.77xVcc IIC_writecmd(0x8d);//--set DC-DC enable IIC_writecmd(0x14);// IIC_writecmd(0xaf);//--turn on oled panel LCD_CLS(); LCD_Set_Pos(0,0); } //在指定位置显示一个字符,包括部分字符 //x:0~127 //y:0~63 //mode:0,反白显示;1,正常显示 //size:选择字体 16/12 void LCD_ShowChar(unsigned char x,unsigned char y,unsigned char chr,unsigned char Char_Size) { unsigned char c=0,i=0; c=chr-' ';//得到偏移后的值 if(x>Max_Column-1) { x=0; y=y+2; } if(Char_Size ==16) { LCD_Set_Pos(x,y); for(i=0;i<8;i++) IIC_writedata(F8X16[c*16+i]); LCD_Set_Pos(x,y+1); for(i=0;i<8;i++) IIC_writedata(F8X16[c*16+i+8]); } else { LCD_Set_Pos(x,y); for(i=0;i<6;i++) IIC_writedata(F6x8[c][i]); } } //显示一个字符号串 void LCD_ShowString(unsigned char x,unsigned char y,unsigned char *chr,unsigned char Char_Size) { unsigned char j=0; while (chr[j]!='\0') { LCD_ShowChar(x,y,chr[j],Char_Size); x+=8; if(x>128) { x=0; y+=2; } j++; } } //m^n函数 unsigned long oled_pow(unsigned char m,unsigned char n) { unsigned long result=1; while(n--)result*=m; return result; } //显示一个数字 void LCD_ShowNum(unsigned char x,unsigned char y,unsigned long num,unsigned char len,unsigned char size2) { unsigned char t,temp; //unsigned char enshow=0; for(t=0;t<len;t++) { temp=(num/oled_pow(10,len-t-1))%10; /*if(enshow==0&&t<(len-1)) { if(temp==0) { LCD_ShowChar(x+(size2/2)*t,y,' ',size2); continue; }else enshow=1; }*/ LCD_ShowChar(x+(size2/2)*t,y,temp+'0',size2); } } main.c #include "IIC.h" #include "font.h" //IIC延时函数 void IIC_delayus(unsigned int i) { unsigned int j,k; for(k=0;k<i;k++) for(j=0;j<4;j++); } //IIC初始化函数 void IIC_ioinit() { P6DIR |= BIT1 | BIT5; // 配置为输出 P6OUT &= ~(BIT1 | BIT5); // 初始低电平 P6REN |= BIT1 | BIT5; // 启用内部上拉 } //开始一个IIC通信 void IIC_start() { SCL_HIGH; SDA_HIGH; //IIC_delayus(2); SDA_LOW; //IIC_delayus(2); SCL_LOW; } //停止IIC通信 void IIC_stop() { SCL_LOW; SDA_LOW; //IIC_delayus(2); SCL_HIGH; SDA_HIGH; //IIC_delayus(2); } //IIC发送一个byte void IIC_writebyte(unsigned char IIC_byte) { unsigned char i; for(i=0;i<8;i++) { if(IIC_byte&0x80) SDA_HIGH; else SDA_LOW; SCL_HIGH; SCL_LOW; IIC_byte<<=1; //loop } SDA_HIGH; SCL_HIGH; SCL_LOW; } void IIC_writecmd(unsigned char IIC_command) { IIC_start(); IIC_writebyte(0x78); //Slave address,SA0=0 IIC_writebyte(0x00); //write command IIC_writebyte(IIC_command); IIC_stop(); } void IIC_writedata(unsigned char IIC_data) { IIC_start(); IIC_writebyte(0x78); IIC_writebyte(0x40); //write data IIC_writebyte(IIC_data); IIC_stop(); } /**************************LCD 设置坐标*******************************/ void LCD_Set_Pos(unsigned char x, unsigned char y) { IIC_writecmd(0xb0+y); IIC_writecmd(((x&0xf0)>>4)|0x10); IIC_writecmd((x&0x0f)|0x01); } /***************************LCD复位************************************/ void LCD_CLS(void) { unsigned char y,x; for(y=0;y<8;y++) { IIC_writecmd(0xb0+y); IIC_writecmd(0x01); IIC_writecmd(0x10); for(x=0;x<X_WIDTH;x++) IIC_writedata(0); } } /***************************LCD初始化************************************/ void LCD_Init(void) { IIC_ioinit(); IIC_writecmd(0xAE); //display off IIC_writecmd(0x20); //Set Memory Addressing Mode IIC_writecmd(0x10); //00,Horizontal Addressing Mode;01,Vertical Addressing Mode;10,Page Addressing Mode (RESET);11,Invalid IIC_writecmd(0xb0); //Set Page Start Address for Page Addressing Mode,0-7 IIC_writecmd(0xc8); //Set COM Output Scan Direction IIC_writecmd(0x00);//---set low column address IIC_writecmd(0x10);//---set high column address IIC_writecmd(0x40);//--set start line address IIC_writecmd(0x81);//--set contrast control register IIC_writecmd(0x7f); IIC_writecmd(0xa1);//--set segment re-map 0 to 127 IIC_writecmd(0xa6);//--set normal display IIC_writecmd(0xa8);//--set multiplex ratio(1 to 64) IIC_writecmd(0x3F);// IIC_writecmd(0xa4);//0xa4,Output follows RAM content;0xa5,Output ignores RAM content IIC_writecmd(0xd3);//-set display offset IIC_writecmd(0x00);//-not offset IIC_writecmd(0xd5);//--set display clock divide ratio/oscillator frequency IIC_writecmd(0xf0);//--set divide ratio IIC_writecmd(0xd9);//--set pre-charge period IIC_writecmd(0x22); // IIC_writecmd(0xda);//--set com pins hardware configuration IIC_writecmd(0x12); IIC_writecmd(0xdb);//--set vcomh IIC_writecmd(0x20);//0x20,0.77xVcc IIC_writecmd(0x8d);//--set DC-DC enable IIC_writecmd(0x14);// IIC_writecmd(0xaf);//--turn on oled panel LCD_CLS(); LCD_Set_Pos(0,0); } //在指定位置显示一个字符,包括部分字符 //x:0~127 //y:0~63 //mode:0,反白显示;1,正常显示 //size:选择字体 16/12 void LCD_ShowChar(unsigned char x,unsigned char y,unsigned char chr,unsigned char Char_Size) { unsigned char c=0,i=0; c=chr-' ';//得到偏移后的值 if(x>Max_Column-1) { x=0; y=y+2; } if(Char_Size ==16) { LCD_Set_Pos(x,y); for(i=0;i<8;i++) IIC_writedata(F8X16[c*16+i]); LCD_Set_Pos(x,y+1); for(i=0;i<8;i++) IIC_writedata(F8X16[c*16+i+8]); } else { LCD_Set_Pos(x,y); for(i=0;i<6;i++) IIC_writedata(F6x8[c][i]); } } //显示一个字符号串 void LCD_ShowString(unsigned char x,unsigned char y,unsigned char *chr,unsigned char Char_Size) { unsigned char j=0; while (chr[j]!='\0') { LCD_ShowChar(x,y,chr[j],Char_Size); x+=8; if(x>128) { x=0; y+=2; } j++; } } //m^n函数 unsigned long oled_pow(unsigned char m,unsigned char n) { unsigned long result=1; while(n--)result*=m; return result; } //显示一个数字 void LCD_ShowNum(unsigned char x,unsigned char y,unsigned long num,unsigned char len,unsigned char size2) { unsigned char t,temp; //unsigned char enshow=0; for(t=0;t<len;t++) { temp=(num/oled_pow(10,len-t-1))%10; /*if(enshow==0&&t<(len-1)) { if(temp==0) { LCD_ShowChar(x+(size2/2)*t,y,' ',size2); continue; }else enshow=1; }*/ LCD_ShowChar(x+(size2/2)*t,y,temp+'0',size2); } } 请分析为什么OLED屏上会显示Vpp=7293mV这一不合理的数值
05-28
Main主程序 #include "sys.h" #include "delay.h" #include "adc.h" #include "gpio.h" #include "OLED_I2C.h" #include "stmflash.h" #include "ds18b20.h" #include "timer.h" #include "usart1.h" #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdbool.h> #define FLASH_SAVE_ADDR ((u32)0x0800F000) //设置FLASH 保存地址(必须为偶数) #define STM32_RX1_BUF Usart1RecBuf #define STM32_Rx1Counter RxCounter #define STM32_RX1BUFF_SIZE USART1_RXBUFF_SIZE extern const unsigned char BMP1[]; extern const unsigned char BMP2[]; char display[16]; //显示缓存区 short temperature=0; //温度 u8 setTempValue = 40; //温度上限 u8 setSmokeValue = 60; //烟雾上限 u8 sendSmsFlag = 0; //发送短信标志 u8 alarmFlag = 0x00; //蜂鸣器报警标志 u16 smoke=0; //烟雾 u8 setn=0; //记录设置按键按下的次数 bool shanshuo=0; bool shuaxin=0; bool fangdao=0; char PhoneNumber[11];//手机号码 char uniPhoneNum[44];//手机号码转码后存放数组 void UsartRx1BufClear(void) { memset(STM32_RX1_BUF, 0, STM32_RX1BUFF_SIZE);//清除缓存 STM32_Rx1Counter = 0; } /***********************************************************************************************/ /****************************** 以下为SIM800相关部分 ****************************************/ /***********************************************************************************************/ void PhoneNumChangeUnicode(char *str1,char *str2) //手机号转码 { u8 i; char *buf = str1; for(i = 0;i < 11;i ++) //发送中文短信手机号必须转码,前面需要加上003 { str2[i*4+0] = '0'; str2[i*4+1] = '0'; str2[i*4+2] = '3'; str2[i*4+3] = buf[i]; } } void gsm_atcmd_send(char *at)//GSM AT指令发送函数 { unsigned short waittry;//延时变量 do { gsm_rev_start = 0;//接收开始标志清零 gsm_rev_okflag = 0;//接收完成标志清零 waittry = 0;//延时变量清零 uart1_send((unsigned char *)at,0xFF);//串口发送内容 while(waittry ++ < 3000)//进入while延时 { if (gsm_rev_okflag == 1)//等待GSM返回OK { return;//返回出去 } delay_ms(1); } } while(gsm_rev_okflag == 0); } void gsm_init(void)//gsm初始化 { gsm_atcmd_send("AT\r\n");//测试用的 delay_ms(1000); gsm_atcmd_send("AT+CSCS=\"UCS2\"\r\n");//设置为unicode编码 delay_ms(1000); gsm_atcmd_send("AT+CMGF=1\r\n");//设置为文本模式 delay_ms(1000); gsm_atcmd_send("AT+CNMI=2,1\r\n");//来短信时提示,并存储到模块内存 delay_ms(1000); gsm_atcmd_send("AT+CMGD=1,4\r\n");//清除短信 delay_ms(1000); gsm_atcmd_send("AT+CSMP=17,0,2,25\r\n");//设置短信保留为5分钟,发送中文 } /* *number 为对方手机号 */ void gsm_send_msg(const char*number,char * content) { u8 len; unsigned char gsm_at_txbuf[60];//GSM AT命令缓存区 memset(gsm_at_txbuf, 0, 60);//缓存清零 strncpy((char *)gsm_at_txbuf,"AT+CMGS=\"",9);//将AT+CMGS=\",复制到gsm_at_txbuf memcpy(gsm_at_txbuf + 9, number, 44);//将手机号码复制到AT+CMGS=\"之后 len = strlen((char *)gsm_at_txbuf);//获取gsm_at_txbuf字符串长度 gsm_at_txbuf[len] = '"'; // AT+CMGS=\"12345678901\" gsm_at_txbuf[len + 1] = '\r'; gsm_at_txbuf[len + 2] = '\n';//gsm_at_txbuf最终的格式"AT+CMGS=\"手机号码\"\r\n" uart1_send(gsm_at_txbuf,0xFF);//发送需要接受短信的手机号码 delay_ms(1000); uart1_send((unsigned char *)content,0xFF); //发短信内容 delay_ms(100); printf("%c",0x1a); //发送结束符号 delay_ms(10); } /* *content 为短信内容 */ void sim800_send_sms(char *content) { bool send_error = 0; u16 send_count = 0; gsm_rev_okflag = 0; OLED_ShowStr(32,2,"Send Sms... ",2,0); PhoneNumChangeUnicode(PhoneNumber,uniPhoneNum); //在发送短信前,先将手机号转码 gsm_send_msg(uniPhoneNum,content);//发送短信 delay_ms(1000);//延时1秒 while(gsm_rev_okflag == 0)//等待返回OK指令 { if(send_count++ > 8000) { send_count = 0; send_error = 1; break; } delay_ms(1); }; gsm_rev_okflag = 0; if(send_error == 1) OLED_ShowStr(32,2,"Send Fail! ",2,0);//显示发送超时 else OLED_ShowStr(32,2," Send OK! ",2,0); UsartRx1BufClear(); delay_ms(1000);//延时1秒 OLED_ShowStr(32,2," ",2,0); } /***********************************************************************************************/ /****************************** end ****************************************/ /***********************************************************************************************/ void STM32_FlashCheck(void) // 检查是否是新的单片机,是的话清空存储区,否则保留 { u8 comper_str[6],i; STMFLASH_Read(FLASH_SAVE_ADDR + 0x10,(u16*)comper_str,5); comper_str[5] = '\0'; if(strstr((char *)comper_str,"FDYDZ") == NULL) //新的单片机 { STMFLASH_Write(FLASH_SAVE_ADDR + 0x10,(u16*)"FDYDZ",5); //写入“FDYDZ”,方便下次校验 delay_ms(50); STMFLASH_Write(FLASH_SAVE_ADDR + 0x40,(u16*)"12345678910",11);//存入初始手机号 delay_ms(50); } STMFLASH_Read(FLASH_SAVE_ADDR + 0x40,(u16*)PhoneNumber,11); //读出手机号 for(i = 0; i < 11 ; i++) { if(PhoneNumber[i]<'0' || PhoneNumber[i]>'9') { break; } } if(i != 11) { memset(PhoneNumber, 0 , 11); //清除缓存 sprintf(PhoneNumber,"12345678910"); } delay_ms(100); } void display_mode(void) { u8 i; //显示中文: 防盗模式 if(fangdao==1){for(i = 0;i < 4;i ++)OLED_ShowCN(i*16+32,0,i+0,1);}else {for(i = 0;i < 4;i ++)OLED_ShowCN(i*16+32,0,i+24,1);} } void displayInitInterface(void) //显示初始页面 { u8 i; for(i = 0;i < 2;i ++)OLED_ShowCN(i*16,4,i+6,0); //显示中文: 温度 for(i = 0;i < 2;i ++)OLED_ShowCN(i*16,6,i+8,0); //显示中文: 烟雾 OLED_ShowChar(32,0,':',2,0); OLED_ShowChar(32,4,':',2,0); OLED_ShowChar(32,6,':',2,0); display_mode(); } void Get_Temperature(void) //获取温度 { temperature=ReadTemperature(); if(temperature>=setTempValue) { if(!(alarmFlag&0x01)) { alarmFlag|=0x01; shanshuo = 0; sendSmsFlag = 2; //发送短信标志 } } else { alarmFlag&=0xFE; } if(temperature>=setTempValue && shanshuo) { OLED_ShowStr(40, 4," ", 2,0); } else { sprintf(display," %d",temperature); OLED_ShowStr(40, 4, (u8*)display, 2,0);//显示温度 OLED_ShowCentigrade(68, 4); //显示摄氏度 } } void Get_Smoke(void) //获取烟雾浓度 { u16 test_adc=0; /* 获取烟雾浓度 */ test_adc = Get_Adc_Average(ADC_Channel_9,10);//读取通道9的10次AD平均值 smoke = test_adc*99/4096;//转换成0-99百分比 if(smoke>=setSmokeValue) { if(!(alarmFlag&0x02)) { alarmFlag|=0x02; shanshuo = 0; sendSmsFlag = 3; //发送短信标志 } } else { alarmFlag&=0xFD; } if(smoke>=setSmokeValue && shanshuo) { OLED_ShowStr(40, 6," ", 2,0); } else { sprintf(display," %02d %%",smoke); OLED_ShowStr(40, 6, (u8*)display, 2,0);//显示温度 } } void displaySetValue(void) //显示设置值 { u8 add=2,i; if(setn==1) { OLED_ShowChar(56,4,setTempValue%100/10+'0',2,0);//显示 OLED_ShowChar(64,4,setTempValue%10+'0',2,0);//显示 } if(setn==2) { OLED_ShowChar(56,4,setSmokeValue%100/10+'0',2,0);//显示 OLED_ShowChar(64,4,setSmokeValue%10+'0',2,0);//显示 OLED_ShowChar(72,4,'%',2,0); } if(setn>=3) { for(i = 0;i < 11;i ++) { OLED_ShowChar((add++)*8,4,PhoneNumber[i],2,(setn+1)-(3+i));//显示手机号码 } } } void keyscan(void) //按键扫描 { u8 i; if(KEY1 == 0) //设置键 { delay_ms(20); if(KEY1 == 0) { while(KEY1 == 0); setn ++; if(setn == 1) { OLED_CLS();//清屏 for(i = 0;i < 4;i ++)OLED_ShowCN(i*16+32,0,i+10,0);//显示中文:设置温度 OLED_ShowCentigrade(75, 4); //显示摄氏度 } if(setn == 2) { for(i = 0;i < 4;i ++)OLED_ShowCN(i*16+32,0,i+14,0);//显示中文:设置烟雾 OLED_ShowChar(80,4,' ',2,0); } if(setn == 3) { for(i = 0;i < 6;i ++)OLED_ShowCN(i*16+16,0,i+18,0);//显示中文:设置手机号码 } if(setn >= 14) { setn = 0; OLED_CLS();//清屏 displayInitInterface(); STMFLASH_Write(FLASH_SAVE_ADDR + 0x40,(u16*)PhoneNumber,11); //退出设置,存入设置的手机号 } displaySetValue(); } } if(KEY2 == 0) //加键 { delay_ms(80); if(KEY2 == 0) { if(setTempValue < 99 && setn==1)setTempValue++; if(setSmokeValue < 99 && setn==2)setSmokeValue++; if(setn>=3) { PhoneNumber[setn-3]++; if(PhoneNumber[setn-3]>'9')PhoneNumber[setn-3]='0'; } displaySetValue(); } } if(KEY3 == 0) //减键 { delay_ms(80); if(KEY3 == 0) { if(setn==0) { fangdao=!fangdao; display_mode(); } if(setTempValue > 0 && setn==1)setTempValue--; if(setSmokeValue > 0 && setn==2)setSmokeValue--; if(setn>=3) { PhoneNumber[setn-3]--; if(PhoneNumber[setn-3]<'0')PhoneNumber[setn-3]='9'; } displaySetValue(); } } } int main(void) { bool flameFlag=0; bool SomebodyFlag=0; char SEND_BUF[400]; //发送短信缓存 delay_init(); //延时函数初始化 NVIC_Configuration(); //中断优先级配置 I2C_Configuration(); //IIC初始化 STM32_FlashCheck(); //FLASH初始化 delay_ms(200); OLED_Init(); //OLED液晶初始化 OLED_CLS(); //清屏 OLED_ShowStr(0,2," GSM Init... ",2,0); uart1_Init(9600); gsm_init();//gsm初始化 OLED_CLS();//清屏 Adc_Init(); //adc初始化 KEY_GPIO_Init(); //按键引脚初始化 SR501_GPIO_Init(); //人体红外初始化 DS18B20_GPIO_Init(); //温度初始化 DS18B20_Init(); //初始化显示 displayInitInterface(); //显示初始界面 TIM3_Init(99,719); //定时器初始化,定时1ms //Tout = ((arr+1)*(psc+1))/Tclk ; //Tclk:定时器输入频率(单位MHZ) //Tout:定时器溢出时间(单位us) while(1) { keyscan(); //按键扫描 if(setn == 0) { if(shuaxin == 1) //大概300ms刷新一次数据 { Get_Temperature(); //获取温度 Get_Smoke(); //获取烟雾 shuaxin = 0; } if(FLAME == 0) //检测到火焰 { delay_ms(10); if(FLAME == 0) { if(flameFlag == 0) { OLED_DrawBMP(88,4,120,8,(unsigned char *)BMP1); //显示火焰图片 sendSmsFlag = 1; //发送短信标志 } flameFlag = 1; } } else { if(flameFlag == 1) { OLED_ShowStr(88, 4, " ", 2,0); OLED_ShowStr(88, 6, " ", 2,0); } flameFlag = 0; } if(fangdao==1&&SR501==1) //在防盗模式下检测到有人 { if(SomebodyFlag==0) { OLED_DrawBMP(0,0,32,4,(unsigned char *)BMP2); //图显示 sendSmsFlag = 4; //发送短信标志 SomebodyFlag = 1; } } else { if(SomebodyFlag==1) { OLED_ShowStr(0, 0, " ", 2,0); OLED_ShowStr(0, 2, " ", 2,0); SomebodyFlag = 0; } } if(temperature>=setTempValue || smoke>=setSmokeValue || flameFlag || SomebodyFlag)BEEP=1;else BEEP=0; //检测到温度烟雾超标火焰蜂鸣器报警 if(temperature>=setTempValue)FAN=1;else FAN=0; //温度超标都开启风扇 if(smoke>=setSmokeValue || flameFlag)RELAY = 1; else RELAY = 0; //检测到有火或者烟雾超标,开启水泵 if(sendSmsFlag != 0) //发送短信 { char TEMP_BUF[100]; /*******************************************************************************************/ /*******************以下为短信内容处理部分,发送中文短信必须转换为Unicode码**************/ /******************************************************************************************/ memset(SEND_BUF,0,sizeof(SEND_BUF)); //清空缓冲区 switch(sendSmsFlag) { case(1): strcat(SEND_BUF,"8B66544AFF0168C06D4B5230706B7130FF01"); break; //警告!检测到火焰! case(2): strcat(SEND_BUF,"8B66544AFF016E295EA68FC79AD8FF01"); break; //警告!温度过高! case(3): strcat(SEND_BUF,"8B66544AFF0170DF96FE6D535EA68FC79AD8FF01"); break; //警告!烟雾浓度过高! case(4): strcat(SEND_BUF,"8B66544AFF0168C06D4B523067094EBAFF01"); break; //警告!检测到有人! default: break; } if(sendSmsFlag!=4) { memset(TEMP_BUF,0,sizeof(TEMP_BUF)); //清空缓冲区 sprintf(TEMP_BUF,"6E295EA6003A003%1d003%1d2103FF0C70DF96FE003A003%1d003%1d0025",temperature/10,temperature%10,smoke/10,smoke%10); strcat(SEND_BUF,TEMP_BUF); } sim800_send_sms((char *)SEND_BUF);//发送短信 sendSmsFlag = 0; /*******************************************************************************************/ /*************************** end *****************************/ /******************************************************************************************/ } } delay_ms(10); } } void TIM3_IRQHandler(void)//定时器3中断服务程序,用于记录时间 { static u16 timeCount1 = 0; if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查指定的TIM中断发生与否:TIM 中断源 { TIM_ClearITPendingBit(TIM3, TIM_IT_Update); //清除中断标志位 timeCount1++; if(timeCount1 >= 300) //300ms { timeCount1 = 0; shanshuo = !shanshuo; shuaxin = 1; } } } ADC初始化程序 #include "adc.h" #include "delay.h" //初始化ADC //这里我们仅以规则通道为例 //我们默认将开启通道0~3 void Adc_Init(void) { ADC_InitTypeDef ADC_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB |RCC_APB2Periph_ADC1 , ENABLE ); //使能ADC1通道时钟 RCC_ADCCLKConfig(RCC_PCLK2_Div8); //设置ADC分频因子6 72M/8=9,ADC最大时间不能超过14M GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1|GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模拟输入引脚 GPIO_Init(GPIOB, &GPIO_InitStructure); ADC_DeInit(ADC1); //复位ADC1,将外设 ADC1 的全部寄存器重设为缺省值 ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //ADC工作模式:ADC1和ADC2工作在独立模式 ADC_InitStructure.ADC_ScanConvMode = DISABLE; //模数转换工作在单通道模式 ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //模数转换工作在单次转换模式 ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //转换由软件而不是外部触发启动 ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //ADC数据右对齐 ADC_InitStructure.ADC_NbrOfChannel = 1; //顺序进行规则转换的ADC通道的数目 ADC_Init(ADC1, &ADC_InitStructure); //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器 ADC_Cmd(ADC1, ENABLE); //使能指定的ADC1 ADC_ResetCalibration(ADC1); //使能复位校准 while(ADC_GetResetCalibrationStatus(ADC1)); //等待复位校准结束 ADC_StartCalibration(ADC1); //开启AD校准 while(ADC_GetCalibrationStatus(ADC1)); //等待校准结束 } //获得ADC值 //ch:通道值 9 u16 Get_Adc(u8 ch) { //设置指定ADC的规则组通道,一个序列,采样时间 ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_71Cycles5 ); //ADC1,ADC通道,采样时间为13.5周期 ADC_SoftwareStartConvCmd(ADC1, ENABLE); //使能指定的ADC1的软件转换启动功能 while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束 return ADC_GetConversionValue(ADC1); //返回最近一次ADC1规则组的转换结果 } u16 Get_Adc_Average(u8 ch,u8 times) { u32 temp_val=0; u8 t; for(t=0;t<times;t++) { temp_val+=Get_Adc(ch); delay_ms(5); } return temp_val/times; } #ifndef __ADC_H #define __ADC_H #include "sys.h" void Adc_Init(void); u16 Get_Adc(u8 ch); u16 Get_Adc_Average(u8 ch,u8 times); #endif GPIO引脚初始化程序 #include "gpio.h" ////////////////////////////////////////////////////////////////////////////////// //按键舵机的GPIO设置 ////////////////////////////////////////////////////////////////////////////////// void KEY_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOC|RCC_APB2Periph_AFIO, ENABLE); //使能PABC端口时钟 GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE); //关闭JTAG模式 使PB3,PB4变成普通IO口 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15; // 端口配置 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入 GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15; // 端口配置 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz GPIO_Init(GPIOC, &GPIO_InitStructure); GPIO_ResetBits(GPIOC,GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15); //输出0 } void SR501_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能PA端口时钟 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; // 端口配置 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //下拉输入 GPIO_Init(GPIOA, &GPIO_InitStructure); } #ifndef __GPIO_H #define __GPIO_H #include "sys.h" #define KEY1 PBin(12) #define KEY2 PBin(13) #define KEY3 PBin(14) #define FLAME PBin(15) #define BEEP PCout(13) #define FAN PCout(14) #define RELAY PCout(15) #define SR501 PAin(0) void KEY_GPIO_Init(void);//引脚初始化 void SR501_GPIO_Init(void); #endif OLED驱动程序 /************************************************************************************ * * Description:128*64点阵的OLED显示屏驱动文件SD1306驱动IIC通信方式显示屏 * * Others: none; * * Function List: * 1. void I2C_Configuration(void) -- 配置CPU的硬件I2C * 2. void I2C_WriteByte(uint8_t addr,uint8_t data) -- 向寄存器地址写一个byte的数据 * 3. void WriteCmd(unsigned char I2C_Command) -- 写命令 * 4. void WriteDat(unsigned char I2C_Data) -- 写数据 * 5. void OLED_Init(void) -- OLED屏初始化 * 6. void OLED_SetPos(unsigned char x, unsigned char y) -- 设置起始点坐标 * 7. void OLED_Fill(unsigned char fill_Data) -- 全屏填充 * 8. void OLED_CLS(void) -- 清屏 * 9. void OLED_ON(void) -- 唤醒 * 10. void OLED_OFF(void) -- 睡眠 * 11. void OLED_ShowStr(unsigned char x, unsigned char y, unsigned char ch[], unsigned char TextSize) -- 显示字符串(字体大小有6*8和8*16两种) * 12. void OLED_ShowCN(unsigned char x, unsigned char y, unsigned char N) -- 显示中文(中文需要先取模,然后放到codetab.h中) * 13. void OLED_DrawBMP(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char BMP[]) -- BMP图片 * * History: none; * *************************************************************************************/ #include "OLED_I2C.h" #include "delay.h" #include "codetab.h" /* 定义I2C总线连接的GPIO端口, 用户只需要修改下面4行代码即可任意改变SCL和SDA的引脚 */ #define RCC_I2C_PORT RCC_APB2Periph_GPIOB /* GPIO端口时钟 */ #define PORT_I2C_SCL GPIOB /* GPIO端口 */ #define PIN_I2C_SCL GPIO_Pin_6 /* GPIO引脚 */ #define PORT_I2C_SDA GPIOB /* GPIO端口 */ #define PIN_I2C_SDA GPIO_Pin_7 /* GPIO引脚 */ #define I2C_SCL_PIN GPIO_Pin_6 /* 连接到SCL时钟线的GPIO */ #define I2C_SDA_PIN GPIO_Pin_7 /* 连接到SDA数据线的GPIO */ /* 定义读写SCL和SDA的宏 */ #define I2C_SCL_1() PORT_I2C_SCL->BSRR = I2C_SCL_PIN /* SCL = 1 */ #define I2C_SCL_0() PORT_I2C_SCL->BRR = I2C_SCL_PIN /* SCL = 0 */ #define I2C_SDA_1() PORT_I2C_SDA->BSRR = I2C_SDA_PIN /* SDA = 1 */ #define I2C_SDA_0() PORT_I2C_SDA->BRR = I2C_SDA_PIN /* SDA = 0 */ #define I2C_SDA_READ() ((PORT_I2C_SDA->IDR & I2C_SDA_PIN) != 0) /* 读SDA口线状态 */ #define I2C_SCL_READ() ((PORT_I2C_SCL->IDR & I2C_SCL_PIN) != 0) /* 读SCL口线状态 */ /* ********************************************************************************************************* * 函 数 名: bsp_InitI2C * 功能说明: 配置I2C总线的GPIO,采用模拟IO的方式实现 * 形 参: 无 * 返 回 值: 无 ********************************************************************************************************* */ void bsp_InitI2C_2(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_I2C_PORT, ENABLE); /* 打开GPIO时钟 */ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; /* 开漏输出模式 */ GPIO_InitStructure.GPIO_Pin = PIN_I2C_SCL; GPIO_Init(PORT_I2C_SCL, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = PIN_I2C_SDA; GPIO_Init(PORT_I2C_SDA, &GPIO_InitStructure); /* 给一个停止信号, 复位I2C总线上的所有设备到待机模式 */ i2c_Stop_2(); } /* ********************************************************************************************************* * 函 数 名: i2c_Start * 功能说明: CPU发起I2C总线启动信号 * 形 参: 无 * 返 回 值: 无 ********************************************************************************************************* */ void i2c_Start_2(void) { /* 当SCL高电平时,SDA出现一个下跳沿表示I2C总线启动信号 */ I2C_SDA_1(); I2C_SCL_1(); delay_us(4); I2C_SDA_0(); delay_us(4); I2C_SCL_0(); } /* ********************************************************************************************************* * 函 数 名: i2c_Start * 功能说明: CPU发起I2C总线停止信号 * 形 参: 无 * 返 回 值: 无 ********************************************************************************************************* */ void i2c_Stop_2(void) { /* 当SCL高电平时,SDA出现一个上跳沿表示I2C总线停止信号 */ I2C_SDA_0(); I2C_SCL_1(); delay_us(4); I2C_SDA_1(); delay_us(4); } /* ********************************************************************************************************* * 函 数 名: i2c_SendByte * 功能说明: CPU向I2C总线设备发送8bit数据 * 形 参: _ucByte : 等待发送的字节 * 返 回 值: 无 ********************************************************************************************************* */ void i2c_SendByte_2(uint8_t _ucByte) { uint8_t i; /* 先发送字节的高位bit7 */ for (i = 0; i < 8; i++) { if (_ucByte & 0x80) { I2C_SDA_1(); } else { I2C_SDA_0(); } delay_us(2); I2C_SCL_1(); delay_us(2); I2C_SCL_0(); _ucByte <<= 1; /* 左移一个bit */ delay_us(2); } } /* ********************************************************************************************************* * 函 数 名: i2c_ReadByte * 功能说明: CPU从I2C总线设备读取8bit数据 * 形 参: 无 * 返 回 值: 读到的数据 ********************************************************************************************************* */ uint8_t i2c_ReadByte_2(void) { uint8_t i; uint8_t value; /* 读到第1个bit为数据的bit7 */ value = 0; for (i = 0; i < 8; i++) { value <<= 1; I2C_SCL_1();//SCL在高电平期间,数据必须保持稳定 delay_us(2); if (I2C_SDA_READ()) { value++; } I2C_SCL_0(); delay_us(1); } return value; } /* ********************************************************************************************************* * 函 数 名: i2c_WaitAck * 功能说明: CPU产生一个时钟,并读取器件的ACK应答信号 * 形 参: 无 * 返 回 值: 返回0表示正确应答,1表示无器件响应 ********************************************************************************************************* */ uint8_t i2c_WaitAck_2(void) { uint8_t tempTime; I2C_SDA_1(); /* CPU释放SDA总线 */ delay_us(1); I2C_SCL_1(); /* CPU驱动SCL = 1, 此时器件会返回ACK应答 */ delay_us(1); while(I2C_SDA_READ()) { tempTime++; if(tempTime>250) { i2c_Stop_2(); return 1; } } I2C_SCL_0(); return 0; } /* ********************************************************************************************************* * 函 数 名: i2c_Ack * 功能说明: CPU产生一个ACK信号 * 形 参: 无 * 返 回 值: 无 ********************************************************************************************************* */ void i2c_Ack_2(void) { I2C_SDA_0(); /* CPU驱动SDA = 0 */ delay_us(5); I2C_SCL_1(); /* CPU产生1个时钟 */ delay_us(5); I2C_SCL_0(); delay_us(5); I2C_SDA_1(); /* CPU释放SDA总线 */ } /* ********************************************************************************************************* * 函 数 名: i2c_NAck * 功能说明: CPU产生1个NACK信号 * 形 参: 无 * 返 回 值: 无 ********************************************************************************************************* */ void i2c_NAck_2(void) { I2C_SDA_1(); /* CPU驱动SDA = 1 */ delay_us(5); I2C_SCL_1(); /* CPU产生1个时钟 */ delay_us(5); I2C_SCL_0(); delay_us(5); } void I2C_Configuration(void) { bsp_InitI2C_2(); } void I2C_WriteByte(uint8_t addr,uint8_t data) { /* 第1步:发起I2C总线启动信号 */ i2c_Start_2(); /* 第2步:发起控制字节,高7bit是地址,bit0是读写控制位,0表示写,1表示读 */ i2c_SendByte_2(OLED_ADDRESS | I2C_WR); /* 此处是写指令 */ /* 第3步:发送ACK */ i2c_WaitAck_2(); /* 第4步:发送字节地址 */ i2c_SendByte_2(addr); i2c_WaitAck_2(); /* 第5步:开始写入数据 */ i2c_SendByte_2(data); /* 第6步:发送ACK */ i2c_WaitAck_2(); /* 发送I2C总线停止信号 */ i2c_Stop_2(); } void WriteCmd(unsigned char I2C_Command)//写命令 { I2C_WriteByte(0x00, I2C_Command); } void WriteDat(unsigned char I2C_Data)//写数据 { I2C_WriteByte(0x40, I2C_Data); } void OLED_Init(void) { delay_ms(100); //这里的延时很重要 WriteCmd(0xAE); //display off WriteCmd(0x20); //Set Memory Addressing Mode WriteCmd(0x10); //00,Horizontal Addressing Mode;01,Vertical Addressing Mode;10,Page Addressing Mode (RESET);11,Invalid WriteCmd(0xb0); //Set Page Start Address for Page Addressing Mode,0-7 WriteCmd(0xc8); //Set COM Output Scan Direction WriteCmd(0x00); //---set low column address WriteCmd(0x10); //---set high column address WriteCmd(0x40); //--set start line address WriteCmd(0x81); //--set contrast control register WriteCmd(0xff); //亮度调节 0x00~0xff WriteCmd(0xa1); //--set segment re-map 0 to 127 WriteCmd(0xa6); //--set normal display WriteCmd(0xa8); //--set multiplex ratio(1 to 64) WriteCmd(0x3F); // WriteCmd(0xa4); //0xa4,Output follows RAM content;0xa5,Output ignores RAM content WriteCmd(0xd3); //-set display offset WriteCmd(0x00); //-not offset WriteCmd(0xd5); //--set display clock divide ratio/oscillator frequency WriteCmd(0xf0); //--set divide ratio WriteCmd(0xd9); //--set pre-charge period WriteCmd(0x22); // WriteCmd(0xda); //--set com pins hardware configuration WriteCmd(0x12); WriteCmd(0xdb); //--set vcomh WriteCmd(0x20); //0x20,0.77xVcc WriteCmd(0x8d); //--set DC-DC enable WriteCmd(0x14); // WriteCmd(0xaf); //--turn on oled panel } void OLED_SetPos(unsigned char x, unsigned char y) //设置起始点坐标 { WriteCmd(0xb0+y); WriteCmd(((x&0xf0)>>4)|0x10); WriteCmd((x&0x0f)|0x01); } void OLED_Fill(unsigned char fill_Data)//全屏填充 { unsigned char m,n; for(m=0;m<8;m++) { WriteCmd(0xb0+m); //page0-page1 WriteCmd(0x00); //low column start address WriteCmd(0x10); //high column start address for(n=0;n<128;n++) { WriteDat(fill_Data); } } } void OLED_CLS(void)//清屏 { OLED_Fill(0x00); } //-------------------------------------------------------------- // Prototype : void OLED_ON(void) // Calls : // Parameters : none // Description : 将OLED从休眠中唤醒 //-------------------------------------------------------------- void OLED_ON(void) { WriteCmd(0X8D); //设置电荷泵 WriteCmd(0X14); //开启电荷泵 WriteCmd(0XAF); //OLED唤醒 } //-------------------------------------------------------------- // Prototype : void OLED_OFF(void) // Calls : // Parameters : none // Description : 让OLED休眠 -- 休眠模式下,OLED功耗不到10uA //-------------------------------------------------------------- void OLED_OFF(void) { WriteCmd(0X8D); //设置电荷泵 WriteCmd(0X10); //关闭电荷泵 WriteCmd(0XAE); //OLED休眠 } //在指定位置显示一个字符,包括部分字符 //x:0~127 //y:0~7 //chr:显示的字符 //TextSize:字符大小(1:6*8 ; 2:8*16) //mode:1,反白显示;0,正常显示 void OLED_ShowChar(unsigned char x,unsigned char y,unsigned char chr,unsigned char TextSize,u8 mode) { unsigned char c=0,i=0; c=chr-' ';//得到偏移后的值 if(TextSize == 2) { if(x>120){x=0;y++;} OLED_SetPos(x,y); for(i=0;i<8;i++) if(mode==1)WriteDat(~(F8X16[c*16+i]));else WriteDat(F8X16[c*16+i]); OLED_SetPos(x,y+1); for(i=0;i<8;i++) if(mode==1)WriteDat(~(F8X16[c*16+i+8]));else WriteDat(F8X16[c*16+i+8]); } else { if(x>126){x=0;y++;} OLED_SetPos(x,y); for(i=0;i<6;i++) if(mode==1)WriteDat(~(F6x8[c][i])); else WriteDat(F6x8[c][i]); } } //-------------------------------------------------------------- // Prototype : void OLED_ShowChar(unsigned char x, unsigned char y, unsigned char ch[], unsigned char TextSize) // Calls : // Parameters : x,y -- 起始点坐标(x:0~127, y:0~7); ch[] -- 要显示的字符串; TextSize -- 字符大小(1:6*8 ; 2:8*16) // Description : 显示codetab.h中的ASCII字符,有6*8和8*16可选择 //-------------------------------------------------------------- void OLED_ShowStr(unsigned char x, unsigned char y, unsigned char ch[], unsigned char TextSize,u8 mode) { unsigned char c = 0,i = 0,j = 0; switch(TextSize) { case 1: { while(ch[j] != '\0') { c = ch[j] - 32; if(x > 126) { x = 0; y++; } OLED_SetPos(x,y); for(i=0;i<6;i++) if(mode==1)WriteDat(~(F6x8[c][i])); else WriteDat(F6x8[c][i]); x += 6; j++; } }break; case 2: { while(ch[j] != '\0') { c = ch[j] - 32; if(x > 120) { x = 0; y++; } OLED_SetPos(x,y); for(i=0;i<8;i++) if(mode==1)WriteDat(~(F8X16[c*16+i])); else WriteDat(F8X16[c*16+i]); OLED_SetPos(x,y+1); for(i=0;i<8;i++) if(mode==1)WriteDat(~(F8X16[c*16+i+8])); else WriteDat(F8X16[c*16+i+8]); x += 8; j++; } }break; } } //-------------------------------------------------------------- // Prototype : void OLED_ShowCN(unsigned char x, unsigned char y, unsigned char N) // Calls : // Parameters : x,y -- 起始点坐标(x:0~127, y:0~7); N:汉字在codetab.h中的索引 // Description : 显示codetab.h中的汉字,16*16点阵 //mode:1,反白显示;0,正常显示 //-------------------------------------------------------------- void OLED_ShowCN(unsigned char x, unsigned char y, unsigned char N,u8 mode) { unsigned char wm=0; unsigned int adder=32*N; OLED_SetPos(x , y); for(wm = 0;wm < 16;wm++) { if(mode==1)WriteDat(~(F16x16[adder]));else WriteDat(F16x16[adder]); adder += 1; } OLED_SetPos(x,y + 1); for(wm = 0;wm < 16;wm++) { if(mode==1)WriteDat(~(F16x16[adder]));else WriteDat(F16x16[adder]); adder += 1; } } //-------------------------------------------------------------- // Prototype : void OLED_DrawBMP(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char BMP[]); // Calls : // Parameters : x0,y0 -- 起始点坐标(x0:0~127, y0:0~7); x1,y1 -- 起点对角线(结束点)的坐标(x1:1~128,y1:1~8) // Description : 显示BMP位图 //-------------------------------------------------------------- void OLED_DrawBMP(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char BMP[]) { unsigned int j=0; unsigned char x,y; if(y1%8==0) y = y1/8; else y = y1/8 + 1; for(y=y0;y<y1;y++) { OLED_SetPos(x0,y); for(x=x0;x<x1;x++) { WriteDat(BMP[j++]); } } } void OLED_ShowCentigrade(unsigned char x, unsigned char y)//显示℃ { unsigned char wm=0; unsigned char BUF[]={ 0x10,0x28,0x10,0xC0,0x20,0x10,0x10,0x10,0x20,0x70,0x00,0x00,0x00,0x00,0x00,0x07, 0x08,0x10,0x10,0x10,0x10,0x08,0x04,0x00,/*"℃"*/ }; OLED_SetPos(x , y); for(wm = 0;wm < 12;wm++) { WriteDat(BUF[wm]); } OLED_SetPos(x,y + 1); for(wm = 0;wm < 12;wm++) { WriteDat(BUF[wm+12]); } } #ifndef __OLED_I2C_H #define __OLED_I2C_H #include "stm32f10x.h" #define OLED_ADDRESS 0x78 //通过调整0R电阻,屏可以0x78和0x7A两个地址 -- 默认0x78 #define I2C_WR 0 /* 写控制bit */ #define I2C_RD 1 /* 读控制bit */ void bsp_InitI2C_2(void); void i2c_Start_2(void); void i2c_Stop_2(void); void i2c_SendByte_2(uint8_t _ucByte); uint8_t i2c_ReadByte_2(void); uint8_t i2c_WaitAck_2(void); void i2c_Ack_2(void); void i2c_NAck_2(void); void I2C_Configuration(void); void I2C_WriteByte(uint8_t addr,uint8_t data); void WriteCmd(unsigned char I2C_Command); void WriteDat(unsigned char I2C_Data); void OLED_Init(void); void OLED_SetPos(unsigned char x, unsigned char y); void OLED_Fill(unsigned char fill_Data); void OLED_CLS(void); void OLED_ON(void); void OLED_OFF(void); void OLED_ShowChar(unsigned char x,unsigned char y,unsigned char chr,unsigned char TextSize,u8 mode); void OLED_ShowStr(unsigned char x, unsigned char y, unsigned char ch[], unsigned char TextSize,u8 mode); void OLED_ShowCN(unsigned char x, unsigned char y, unsigned char N,u8 mode); void OLED_DrawBMP(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char BMP[]); void OLED_ShowCentigrade(unsigned char x, unsigned char y); #endif TIME定时器程序 #include "timer.h" //通用定时器中断初始化 //这里时钟选择为APB1的2倍,而APB1为36M //arr:自动重装值。 //psc:时钟预分频数 //这里使用的是定时器3! void TIM3_Init(u16 arr,u16 psc) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能 TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值 计数到5000为500ms TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值 10Khz的计数频率 TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式 TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位 TIM_ITConfig( //使能或者失能指定的TIM中断 TIM3, //TIM3 TIM_IT_Update , ENABLE //使能 ); NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //TIM3中断 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //先占优先级0级 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //从优先级2级 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能 NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器 TIM_Cmd(TIM3, ENABLE); //使能定时器3 } #ifndef __TIMER_H #define __TIMER_H #include "sys.h" void TIM3_Init(u16 arr,u16 psc); #endif DS18B20温度程序 #include "ds18b20.h" #include "delay.h" /******************************************************************************* 函数名:DS18B20_GPIO_Init 功能:初始化DS18B20引脚 输入: 输出: 返回值: 备注: *******************************************************************************/ void DS18B20_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_DS18B20_PORT, ENABLE); //使能PORTA口时钟 GPIO_InitStructure.GPIO_Pin = DS18B20_GPIO_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(DS18B20_GPIO_PORT, &GPIO_InitStructure); GPIO_SetBits(DS18B20_GPIO_PORT,DS18B20_GPIO_PIN); //输出1 } /******************************************************************************* 函数名:DS18B20_Init 功能:初始化DS18B20 输入: 输出: 返回值:初始化成功为0,不成功为1 备注: *******************************************************************************/ u8 DS18B20_Init(void) { unsigned char wait=0; DS18B20_IO_OUT(); //输出模式 DS18B20_OUT_0; //拉低 delay_us(750); //至少延时480us DS18B20_OUT_1; //拉高 delay_us(15); //15us DS18B20_IO_IN(); //输入模式 while(READ_DS18B20_IO && wait++<200)delay_us(1);//等待高电平结束 if(wait>=200)return 1; else wait=0; while(!READ_DS18B20_IO && wait++<240)delay_us(1);//等待低电平结束 if(wait>=240)return 1; else return 0; } /******************************************************************************* 函数名:DS18B20_ReadByte 功能:从DS18B20读一个字节 输入: 输出: 返回值:读取到的字节 备注: *******************************************************************************/ unsigned char DS18B20_ReadByte(void) { unsigned char i; unsigned char dat = 0; for (i=0; i<8; i++) //8位计数器 { dat >>= 1; DS18B20_IO_OUT(); //输出模式 DS18B20_OUT_0; //开始时间片 delay_us(2); //延时等待 DS18B20_OUT_1; //准备接收 DS18B20_IO_IN(); //输入模式 delay_us(12); //接收延时 if(READ_DS18B20_IO) dat |= 0x80; //读取数据 delay_us(60); //等待时间片结束 } return dat; } /******************************************************************************* 函数名:DS18B20_WriteByte 功能:写一个字节 输入:unsigned char dat 输出: 返回值: 备注: *******************************************************************************/ void DS18B20_WriteByte(unsigned char dat) { unsigned char i; unsigned char temp; DS18B20_IO_OUT();//输出模式 for (i=1; i<=8; i++) { temp = dat & 0x01; dat = dat >> 1; if (temp) { DS18B20_OUT_0; delay_us(2); DS18B20_OUT_1; //写1 delay_us(60); } else { DS18B20_OUT_0;//写0 delay_us(60); DS18B20_OUT_1; delay_us(2); } } } /************************************** 从DS18B20中获取温度值得浮点值 参数: 空 返回值: 读取到的温度值(有效范围-55.0~125.0) **************************************/ float ReadTemperature(void) { unsigned char TPH; //存放温度值的高字节 unsigned char TPL; //存放温度值的低字节 short i16=0; float f32=0; DS18B20_Init(); DS18B20_WriteByte(0xCC); //跳过ROM命令 DS18B20_WriteByte(0x44); //开始转换命令 DS18B20_Init(); DS18B20_WriteByte(0xCC); //跳过ROM命令 DS18B20_WriteByte(0xBE); //读暂存存储器命令 TPL = DS18B20_ReadByte(); //读温度低字节 TPH = DS18B20_ReadByte(); //读温度高字节 i16 = 0; i16 = (TPH<<8) |TPL; // 将高位(MSB)与低位(LSB)合并 f32 = i16 * 0.0625; // 12bit精度时温度值计算 return(f32); // 返回读取到的温度数值(float型) } #ifndef __DS18B20_H #define __DS18B20_H #include "sys.h" //如果想要修改引脚,只需修改下面的宏 #define RCC_DS18B20_PORT RCC_APB2Periph_GPIOA /* GPIO端口时钟 */ #define DS18B20_GPIO_PIN GPIO_Pin_11 #define DS18B20_GPIO_PORT GPIOA //IO方向设置(CRL寄存器对应引脚0~7,CRH寄存器对应引脚8~15) //DS18B20_GPIO_PORT->CRH&=0xFFFFFFF0为PA8引脚输出模式对应的寄存器清空 //DS18B20_GPIO_PORT->CRH|=0x00000008将(CNF8[1:0]设置为10:上拉/下拉输入模式,MODE8[1;0]设置为00:输入模式) //DS18B20_GPIO_PORT->CRH|=0x00000003将(CNF8[1:0]设置为00:通用推挽输出模式 ,MODE8[1;0]设置为11:最大50MHZ) #define DS18B20_IO_IN() {DS18B20_GPIO_PORT->CRH&=0xFFFF0FFF;DS18B20_GPIO_PORT->CRH|=0x00008000;} #define DS18B20_IO_OUT() {DS18B20_GPIO_PORT->CRH&=0xFFFF0FFF;DS18B20_GPIO_PORT->CRH|=0x00003000;} #define DS18B20_OUT_0 GPIO_ResetBits(DS18B20_GPIO_PORT, DS18B20_GPIO_PIN)//IO为低电平 #define DS18B20_OUT_1 GPIO_SetBits(DS18B20_GPIO_PORT, DS18B20_GPIO_PIN)//IO为高电平 #define READ_DS18B20_IO GPIO_ReadInputDataBit(DS18B20_GPIO_PORT, DS18B20_GPIO_PIN)//读取IO电平 void DS18B20_GPIO_Init(void); u8 DS18B20_Init(void); //初始化DS18B20 float ReadTemperature(void); //获取温度值 #endif 修改代码中使用OLED的部分,改为使用LCD1602实现
05-30
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值