首页
📁归档
⏳时光机
📫留言
🚩友链
💰资助名单
推荐
🎧音乐
🏜️ 壁纸
❤ 捐助
Search
1
【NPN/PNP三极管】放大电路饱和失真和截止失真的区别
13,922 阅读
2
论文写作中如何把word里面所有数字和字母替换为新罗马字体
7,794 阅读
3
【高数】形心计算公式讲解大全
7,212 阅读
4
【概论】一阶矩、二阶矩原点矩,中心矩区别与概念
5,668 阅读
5
【1】基于STM32CubeMX-STM32GPIO端口开发
5,667 阅读
🪶微语&随笔
励志美文
我的随笔
写作办公
📡电子&通信
嵌入式&系统
通信&信息处理
编程&脚本笔记
⌨️IC&系统
FPGA&ASIC
VLSI&IC验证
EDA&虚拟机
💻电子&计算机
IP&SOC设计
机器学习
软硬件算法
登录
刘航宇(共306篇)
找到
306
篇与
刘航宇
相关的结果
- 第 13 页
2022-03-13
数字电路基础-最大项与最小项
目录 1.定义 2.性质 3.关系 1.定义 最小项:n个变量的逻辑乘,即与形式,每个变量以原变量或者反变量的形式出现一次。n个变量共有2n个最小项。用m表示,如ABC,表示为m0。 最大项:n个变量的逻辑和,即或形式,每个变量以原变量或者反变量的形式出现一次。n个变量共有2n个最大项。用M表示,如A+B+C,表示为M0。 如下为三变量最小项和最大项的表示方法: 图片 2.性质 对于n个变量来说,若给定这些变量确定的值,那么2n个最小项中仅有一组值为1,其余全为0;2n个最大项中仅有一组值为0,其余全为1. 全部最小项之和恒等于1;全部最大项之积恒等于0。(可由第一条性质中看出) 任意两个最小项之积等于0;任意两个最大项之和等于1。(可由第一条性质中看出) 若干个最小项的和等于其余最小项和的反。简单可以记做为卡诺图上分成两部分,他们之间为反关系。 3.关系 最小项的反是最大项,最大项的反是最小项。 图片
嵌入式&系统
刘航宇
3年前
0
1,605
6
【美文】平常烟火,珍惜一段春色
习惯了,一个人早晨的时候去呼吸新鲜的空气,公园散步,与早起的人们一起,沿着一湾清水,走在幽静的小路上,鸟鸣啾啾,春意缓归,也是惬意。 散步回来,一杯牛奶,几片面包,也就打发了自己。 隔着窗,萧瑟凋零的草木重新焕发生机,醒来时,已是春光乍泄。 光阴似箭,走过曾经的时光,拥抱春天,当最后一片雪花飘落,风霜雨雪便是人生的足迹,一步一步走向美好。 春已至,站在春天里,遥看春色渐暖,浅淡颜色,渐渐有了模样,物候秩序,水墨丹青细细描摹。 枝头的蓓蕾藏,期待着花期,用自己的方式,各自准备着给春天的厚礼。 图片 苏醒的枝蔓,缓缓伸展着腰肢,春意盎然,只是时间问题,那些醉人的风景和迷人的姿态,慢慢的,都会一一到达。 时光不老,却是又重返青春,跟着流云,掠过一帧一帧的花影,在疏影横斜的背景里,日子可以走的亦是轻松,沿着季节的方向,明媚着未来的路途。 凝眸春风过处,款款春意盎然恣意,似淡墨染成的画卷。许多时候,一点灵犀,便是曼妙,在蕾枝之间彼此守护。 就如某种默契,无需言说即可心领神会。就如岁月的枝头,只要春风一来,无论静默多久,都会开出鲜艳的花瓣,释放出一分欢喜和几分明媚。 那画卷里,风景旖旎,千丝万缕细枝,沿途摇暖了一季风景,眸中清寒,也是时光里的潋滟,春来时,轻轻翻开一个个冬天埋下的伏笔,瞬间花苞炸裂,芳菲开遍。 图片 平淡的事情,用心感悟才有了意味深长,万千风景,用心了才是清欢有味。 在最美的时光里,安静知足,对任何喜欢的人或事都学会有所期待,耐心等待,无需刻意,只是顺其自然,只怕不经意间就失去平淡的光泽。 在春天的希望里,看似水流年,看绿肥红瘦,淡然之间,让生命有了柔和的温度。 春在路上,花在枝上,所有的美好都在心上,努力过好自己的日子,冷暖之间,各自安好。 心怀美好,用一份付出与努力,善待自己,接纳生活,摈弃杂念,别让鸡零狗碎的事情,耗尽你对美好生活的向往。 守住生命与自然的本色,自然而然,以淡泊宁静的心态去面对现实,无需仰视枝头的花朵,生活还需简单明了,只是珍爱,与这尘世和睦相处,再多一份心头的默契,如此,甚好。 图片 不念过往,不惧将来,我们无须铭记或者忘记,每一段岁月都是值得拥有的,你曾经拥有过的,都是最好的时光。 活在当下,你看,春风春雨春烟,让山河有了温柔的气息,一花一草一木都是春天的美丽。 平淡日子,让自己安静下来,用最美心情接受春天得到来,缘之所寄,是淡淡时光;一往而深,深情之处,平淡生活也是春天。
励志美文
刘航宇
3年前
1
660
5
2022-03-01
考研数学选填绝杀技巧
本文讲述数学应试考试中常见技巧,希望可以帮到读者 图片 图片 图片
我的随笔
刘航宇
3年前
0
272
3
2022-02-17
【治愈】快来一起看晚霞吧
【治愈】快来一起看晚霞吧-人间仙境
励志美文
刘航宇
3年前
0
178
2
SIM900A发送与接受短信
目录 一.SMS简介 二.短信的控制模式与编码1.Text Mode 2.PDU Mode 3.GSM编码 4.UCS2编码 三.收发英文短信1.AT+CPMS查询短信数量 2.AT+CNMI设置新消息提示类型 3.AT+CMGF选择短信模式 4.AT+CSCS设置编码 5.AT+CSMP设置短信文本模式 6.AT+CMGS发送消息到指定手机号 四.收发中文短信 一.SMS简介 SMS(Short Messaging Service)中文名称短信服务,短信是当下每一部手机上必备的功能之一,顾名思义,它是在手机之间发送文字信息或从个人计算机或手持设备向手机发送信息的一种方式,其文本信息的最大发送量为160个字符(字母、数字或者拉丁字母中的字符),对于中文一般最大发送量为70个字符。 这里我想用SIM900A模块实现短信的收发。 图片 二.短信的控制模式与编码 先说一下:我采用的是Text Mode下使用GSM编码收发英文短信、使用UCS2编码收发中文短信 对于短信的控制一共有三种模式:Block Mode、基于AT指令的Text Mode、基于AT指令的PDU Mode 。目前手机中默认使用PDU Mode,通过PDU编码的短信可以是文字、声音或者图像。Text Mode只能用于发送ANSI范围的字符,发送方式比较简单。 SIM900A模块只提供Text Mode 和PDU Mode。 中文短信中,所有汉字和字符都是采用UNICODE编码。 1.Text Mode Text Mode下,发送及接收到的数据均以ASCII码的显示来表示,可以发送指令"AT+CMGF=1",将GSM短信发送方式更改为文本模式。文本模式下接收的数据会自动解码,比如你收到一条短信息,GSM会返回:+CMGR: “REC UNREAD”,"+8613806XXXXXX",“11/10/21,13:22:13+32” hello (短信内容会自动换行) 不需要自己解码,便可得到短信的发送者、发送时间和短信内容,比较容易操作。 理论上Text Mode下,是只能够收发英文短信,但是SIM900A模块可以在Text Mode下使用UCS2编码,从而可以发送接收中文短信。 2.PDU Mode PDU相当于一个数据包,它由SMS的信息组成,作为一种数据单元,必须包含源地址、目的地址、有效时间、数据格式、协议类型、正文、正文长度(可达140字节),这些信息都以十六进制表示。 PUD Mode被所有手机支持,可以使用任何字符集,其编码方式分为:7bit、8bit、UCS2。 7-bit编码用于发送普通的ASCII字符,它将一串7-bit的字符(最高位为0)编码成8-bit的数据,每8个字符可“压缩”成7个;8-bit编码通常用于发送数据消息,比如图片和铃声等;而UCS2编码用于发送Unicode字符。在这三种编码方式下,PDU串的用户信息(TP-UD)段最大容量(可以发送的短消息的最大字符数)分别是160、140和70。这里,将一个英文字母、一个汉字和一个数据字节都视为一个字符。 理论上发送中文短信需要使用PDU Mode的UCS2编码,上面也说了,SIM900A模块可以使用Text Mode发送UCS2编码,而且PDU Mode比Text Mode更加复杂,所以我采用了Text Mode收发中英文短信。 PDU Mode的详细讲解可以借鉴此博客:点击链接跳转 3.GSM编码 在GSM编码模式下,收发消息的内容和电话号码,都是以ASCII字符的形式显示的,发送英文短信时使用十分方便。 所以我使用GSM编码来收发英文短信。 4.UCS2编码 谈到UCS2编码就不得不说UNICODE,UNICODE又叫统一码、万国码,是计算机科学领域里的一项行业标准,包括字符集、编码方案等。UNICODE 是为了解决传统的字符编码方案的局限而产生的,它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。简单来说,UNICODE编码可以表示世界上任意一种语言(有点夸张),自然也可以表示中文。 而UCS2编码是UNICODE的一种,UCS2中每个字符都占俩个字节。 使用UCS2编码后,发送短信的手机号码、短信内容都要经过UCS2编码转换才可以,但UCS2编码发送的消息在手机上可以直接显示为中文。 所以,需要UCS2与中文的转换软件,如下,可以实现中文和UCS2的双向转换 图片 三.收发英文短信 1.AT+CPMS查询短信数量 图片 2.AT+CNMI设置新消息提示类型 图片 3.AT+CMGF选择短信模式 图片 4.AT+CSCS设置编码 图片 图片 5.AT+CSMP设置短信文本模式 使用Text Mode的GSM编码时,短信文本模式设置为: AT+CSMP=17,167,0,240(消息显示在终端) AT+CSMP=17,167,0,241(消息存储在SIM卡中) 图片 6.AT+CMGS发送消息到指定手机号 使用Text Mode的GSM编码时,直接AT+CMGS="手机号"即可,然后,在>后输入要发送的内容(不要勾选发送新行),最后发送HEX(十六进制)的:1A 即可。 如图,我使用本机向本机发送了一条短信,而且,本机收到短信后在终端中显示出来了。 图片 这是SIM公司给出的例子: 图片 CTRL-Z 代表十六进制:1A 使用SIM900A向本机发送一条英文短信的完整步骤如下: 图片 四.收发中文短信 收发中文短信利用的是Text Mode下的UCS2编码。 相比于收发英文短信,收发中文短信需要修改的地方有: 修改编码:AT+CSCS=“UCS2” 修改短信文本模式:AT+CSMP=17,167,0,24(短消息显示在终端,25:存储在SIM中) 手机号码要用UNICODE码 发送的消息要用UNICODE码(有专门的转换软件) 这是SIM公司给出的例子: 图片 我要发送信息:可爱的小白鼠,女朋友收到后回复消息,用软件将UNICODE码转换为中文,串口操作界面如示: 图片 发消息如示: 图片 收消息如示: 图片 这是我的SIM900A 图片
嵌入式&系统
刘航宇
3年前
0
858
1
2022-02-10
泰戈尔《生如夏花》
图片 生如夏花 泰戈尔 生命,一次又一次轻薄过 轻狂不知疲倦 ——题记 一 我听见回声,来自山谷和心间 以寂寞的镰刀收割空旷的灵魂 不断地重复决绝,又重复幸福 终有绿洲摇曳在沙漠 我相信自己 生来如同璀璨的夏日之花 不凋不败,妖治如火 承受心跳的负荷和呼吸的累赘 乐此不疲 二 我听见音乐,来自月光和胴体 辅极端的诱饵捕获飘渺的唯美 一生充盈着激烈,又充盈着纯然 总有回忆贯穿于世间 我相信自己 死时如同静美的秋日落叶 不盛不乱,姿态如烟 即便枯萎也保留丰肌清骨的傲然 玄之又玄 三 我听见爱情,我相信爱情 爱情是一潭挣扎的蓝藻 如同一阵凄微的风 穿过我失血的静脉 驻守岁月的信念 四 我相信一切能够听见 甚至预见离散,遇见另一个自己 而有些瞬间无法把握 任凭东走西顾,逝去的必然不返 请看我头置簪花,一路走来一路盛开 频频遗漏一些,又深陷风霜雨雪的感动 五 般若波罗蜜,一声一声 生如夏花,死如秋叶 还在乎拥有什么 生如夏花-英文版 Life, thin and light-off time and time again Frivolous tireless one I heard the echo, from the valleys and the heart Open to the lonely soul of sickle harvesting Repeat outrightly, but also repeat the well-being of Eventually swaying in the desert oasis I believe I am Born as the bright summer flowers Do not withered undefeated fiery demon rule Heart rate and breathing to bear the load of the cumbersome Bored Two I heard the music, from the moon and carcass Auxiliary extreme aestheticism bait to capture misty Filling the intense life, but also filling the pure There are always memories throughout the earth I believe I am Died as the quiet beauty of autumn leaves Sheng is not chaos, smoke gesture Even wilt also retained bone proudly Qing Feng muscle Occult Three I hear love, I believe in love Love is a pool of struggling blue-green algae As desolate micro-burst of wind Bleeding through my veins Years stationed in the belief Four I believe that all can hear Even anticipate discrete, I met the other their own Some can not grasp the moment Left to the East to go West, Gu, the dead must not return to See, I head home Zanhua, in full bloom along the way all the way Frequently missed some, but also deeply moved by wind, frost, snow or rain Five Prajna Paramita, soon as soon as Shengruxiahua dead, as an autumn leaf Also care about what has
励志美文
刘航宇
3年前
0
297
3
HAL_STM32_DS18B20开发
1.设置一个如PA0作为DS18B20模块接口 2.添加下面2个文件,注意程序已经集成us延时 ds18b20.c #include "ds18b20.h" static inline void delay_ms(uint32_t delay) { HAL_Delay(delay); } #define CPU_FREQUENCY_MHZ 72 // CPU主频,根据实际进行修改 static void delay_us(uint32_t delay) { int last, curr, val; int temp; while (delay != 0) { temp = delay > 900 ? 900 : delay; last = SysTick->VAL; curr = last - CPU_FREQUENCY_MHZ * temp; if (curr >= 0) { do { val = SysTick->VAL; } while ((val < last) && (val >= curr)); } else { curr += CPU_FREQUENCY_MHZ * 1000; do { val = SysTick->VAL; } while ((val <= last) || (val > curr)); } delay -= temp; } } //复位DS18B20 void DS18B20_Rst(void) { DS18B20_IO_OUT(); //SET PA0 OUTPUT DS18B20_DQ_OUT=0; //拉低DQ delay_us(750); //拉低750us DS18B20_DQ_OUT=1; //DQ=1 delay_us(15); //15US } //等待DS18B20的回应 //返回1:未检测到DS18B20的存在 //返回0:存在 uint8_t DS18B20_Check(void) { uint8_t retry=0; DS18B20_IO_IN();//SET PA0 INPUT while (DS18B20_DQ_IN&&retry<200) { retry++; delay_us(1); }; if(retry>=200)return 1; else retry=0; while (!DS18B20_DQ_IN&&retry<240) { retry++; delay_us(1); }; if(retry>=240)return 1; return 0; } //从DS18B20读取一个位 //返回值:1/0 uint8_t DS18B20_Read_Bit(void) // read one bit { uint8_t data; DS18B20_IO_OUT();//SET PA0 OUTPUT DS18B20_DQ_OUT=0; delay_us(2); DS18B20_DQ_OUT=1; DS18B20_IO_IN();//SET PA0 INPUT delay_us(12); if(DS18B20_DQ_IN)data=1; else data=0; delay_us(50); return data; } //从DS18B20读取一个字节 //返回值:读到的数据 uint8_t DS18B20_Read_Byte(void) // read one byte { uint8_t i,j,dat; dat=0; for (i=1;i<=8;i++) { j=DS18B20_Read_Bit(); dat=(j<<7)|(dat>>1); } return dat; } //写一个字节到DS18B20 //dat:要写入的字节 void DS18B20_Write_Byte(uint8_t dat) { uint8_t j; uint8_t testb; DS18B20_IO_OUT();//SET PA0 OUTPUT; for (j=1;j<=8;j++) { testb=dat&0x01; dat=dat>>1; if (testb) { DS18B20_DQ_OUT=0;// Write 1 delay_us(2); DS18B20_DQ_OUT=1; delay_us(60); } else { DS18B20_DQ_OUT=0;// Write 0 delay_us(60); DS18B20_DQ_OUT=1; delay_us(2); } } } //开始温度转换 void DS18B20_Start(void)// ds1820 start convert { DS18B20_Rst(); DS18B20_Check(); DS18B20_Write_Byte(0xcc);// skip rom DS18B20_Write_Byte(0x44);// convert } //初始化DS18B20的IO口 DQ 同时检测DS的存在 //返回1:不存在 //返回0:存在 uint8_t DS18B20_Init(void) { DS18B20_Rst(); return DS18B20_Check(); } //从ds18b20得到温度值 //精度:0.1C //返回值:温度值 (-550~1250) short DS18B20_Get_Temp(void) { uint8_t temp; uint8_t TL,TH; short tem; DS18B20_Start (); // ds1820 start convert DS18B20_Rst(); DS18B20_Check(); DS18B20_Write_Byte(0xcc);// skip rom DS18B20_Write_Byte(0xbe);// convert TL=DS18B20_Read_Byte(); // LSB TH=DS18B20_Read_Byte(); // MSB if(TH>7) { TH=~TH; TL=~TL; temp=0;//温度为负 }else temp=1;//温度为正 tem=TH; //获得高八位 tem<<=8; tem+=TL;//获得底八位 tem=(float)tem*0.625;//转换 if(temp)return tem; //返回温度值 else return -tem; } ds18b20.h #ifndef __DS18B20_H #define __DS18B20_H #include "main.h" #include "stm32f1xx_hal.h" //#include "delay.h" #define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2)) #define MEM_ADDR(addr) *((volatile unsigned long *)(addr)) #define BIT_ADDR(addr, bitnum) MEM_ADDR(BITBAND(addr, bitnum)) #define GPIOA_ODR_Addr (GPIOA_BASE+12) #define GPIOB_ODR_Addr (GPIOB_BASE+12) #define GPIOC_ODR_Addr (GPIOC_BASE+12) #define GPIOD_ODR_Addr (GPIOD_BASE+12) #define GPIOE_ODR_Addr (GPIOE_BASE+12) #define GPIOF_ODR_Addr (GPIOF_BASE+12) #define GPIOG_ODR_Addr (GPIOG_BASE+12) #define GPIOA_IDR_Addr (GPIOA_BASE+8) #define GPIOB_IDR_Addr (GPIOB_BASE+8) #define GPIOC_IDR_Addr (GPIOC_BASE+8) #define GPIOD_IDR_Addr (GPIOD_BASE+8) #define GPIOE_IDR_Addr (GPIOE_BASE+8) #define GPIOF_IDR_Addr (GPIOF_BASE+8) #define GPIOG_IDR_Addr (GPIOG_BASE+8) #define PAout(n) BIT_ADDR(GPIOA_ODR_Addr,n) #define PAin(n) BIT_ADDR(GPIOA_IDR_Addr,n) #define PBout(n) BIT_ADDR(GPIOB_ODR_Addr,n) #define PBin(n) BIT_ADDR(GPIOB_IDR_Addr,n) #define PCout(n) BIT_ADDR(GPIOC_ODR_Addr,n) #define PCin(n) BIT_ADDR(GPIOC_IDR_Addr,n) #define PDout(n) BIT_ADDR(GPIOD_ODR_Addr,n) #define PDin(n) BIT_ADDR(GPIOD_IDR_Addr,n) #define PEout(n) BIT_ADDR(GPIOE_ODR_Addr,n) #define PEin(n) BIT_ADDR(GPIOE_IDR_Addr,n) #define PFout(n) BIT_ADDR(GPIOF_ODR_Addr,n) #define PFin(n) BIT_ADDR(GPIOF_IDR_Addr,n) #define PGout(n) BIT_ADDR(GPIOG_ODR_Addr,n) #define PGin(n) BIT_ADDR(GPIOG_IDR_Addr,n) //IO方向设置 #define DS18B20_IO_IN() {GPIOA->CRL&=0XFFFFFFF0;GPIOA->CRL|=8<<0;} #define DS18B20_IO_OUT() {GPIOA->CRL&=0XFFFFFFF0;GPIOA->CRL|=3<<0;} //IO操作函数 #define DS18B20_DQ_OUT PAout(0) //数据端口 PA0 #define DS18B20_DQ_IN PAin(0) //数据端口 PA0 uint8_t DS18B20_Init(void); //初始化DS18B20 short DS18B20_Get_Temp(void); //获取温度 void DS18B20_Start(void); //开始温度转换 void DS18B20_Write_Byte(uint8_t dat);//写入一个字节 uint8_t DS18B20_Read_Byte(void); //读出一个字节 uint8_t DS18B20_Read_Bit(void); //读出一个位 uint8_t DS18B20_Check(void); //检测是否存在DS18B20 void DS18B20_Rst(void); //复位DS18B20 #endif程序进行调用 使用温度=DS18B20_Get_Temp();进行调用数值,可见精度达到要求了 图片 图片
嵌入式&系统
刘航宇
3年前
4
1,080
11
2022-01-31
【10】基于STM32CubeMX-STM32ADC与OLED开发
目录 实训案例:ADC与OLED综合训练 实训案例:ADC与OLED综合训练 在XMF07A或XMF07C开发板上,利用STM32CubeMX和Keil5协同开发,完成以下的功能: 【1】 上电开机后,首选在OLED上显示“强国图志”图片,然后让LED1与LED2依次点亮,然后熄灭,进行灯光检测。灯光检测结束后,OLED切换至数据显示界面,分3行: 第1行显示:“ sciarm.com ” 第2行显示:“采样值:” 第3行显示:“电压值:” 【2】在主程序中,采用查询的方式,每隔0.3秒对ADC_IN0通道的光敏传感器进行一次电压数据采集,并将采样到的12位数据换算成对应的实际电压值。LED1作为A/D采样指示灯,每采样一次闪烁一下。 【3】每进行完一次光敏传感器的数据采样和电压换算后,将其结果更新到OLED显示屏中相应的位置。如果光敏传感器的电压值小于1.3V,则将LED2灯点亮,反之,将LED2灯关闭。 图片 //首先需要进行OLED的底层驱动函数移植,生成相应的文字和图片数据 /* USER CODE BEGIN Includes */ //====引入OLED底层驱动的头文件======== #include "XMF_OLED_STM32Cube.h" #include "stdio.h" /* USER CODE END Includes */extern unsigned char BMP1[]; #define LED1_ON() HAL_GPIO_WritePin(GPIOB, GPIO_PIN_9,GPIO_PIN_SET) #define LED2_ON() HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8,GPIO_PIN_SET) #define LED1_OFF() HAL_GPIO_WritePin(GPIOB, GPIO_PIN_9,GPIO_PIN_RESET) #define LED2_OFF() HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8,GPIO_PIN_RESET) uint16_t ADC0_Value = 0; uint16_t ADC_Volt = 0; uint8_t str_buff[64];//LED灯流水点亮检测 void LED_Check() { LED1_ON(); HAL_Delay(500); LED2_ON(); HAL_Delay(500); LED1_OFF(); HAL_Delay(500); LED2_OFF(); HAL_Delay(500); }//显示开机LOGO图片 void OLED_display_pic() { OLED_Clear(); OLED_DrawBMP(0,0,128,8,BMP1); }//显示数据显示界面 void OLED_display_info() { OLED_Clear(); OLED_ShowString(6,0,(uint8_t *)"sciarm.com"); HAL_Delay(200); OLED_ShowCHinese(0,3,24); OLED_ShowCHinese(18,3,25); OLED_ShowCHinese(36,3,26); OLED_ShowString(54,3,(uint8_t *)":"); HAL_Delay(200); OLED_ShowCHinese(0,6,16); OLED_ShowCHinese(18,6,17); OLED_ShowCHinese(36,6,26); OLED_ShowString(54,6,(uint8_t *)":"); HAL_Delay(200); }//更新ADC采样数据与换算结果 void OLED_display_dat() { sprintf((char*)str_buff, "%4d", ADC0_Value); OLED_ShowString(64,3,(uint8_t *)str_buff); sprintf((char*)str_buff, "%d.%d%dV", ADC_Volt/100, (ADC_Volt%100/10), ADC_Volt%10); OLED_ShowString(64,6,(uint8_t *)str_buff); }//ADC采样过程与灯光自动控制 void Get_ADC0_Value() { HAL_ADC_Start(&hadc1); if(HAL_OK == HAL_ADC_PollForConversion(&hadc1, 30)) { ADC0_Value = HAL_ADC_GetValue(&hadc1); ADC_Volt = ADC0_Value * 330 / 4096; if(ADC_Volt < 130) { LED2_ON(); } else { LED2_OFF(); } } HAL_ADC_Stop(&hadc1); }/* USER CODE BEGIN 2 */ OLED_Init(); //初始化OLED OLED_display_pic(); //显示开机LOGO图片 LED_Check(); //灯光检测 OLED_display_info(); //显示数据界面 /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { LED1_ON(); //ADC采样指示灯点亮 Get_ADC0_Value(); //进行一次ADC采样及逻辑处理 OLED_display_dat(); //更新OLED中的采样数据 HAL_Delay(200); //延时0.2秒 LED1_OFF(); //ADC采样指示灯关闭 /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */
嵌入式&系统
# 嵌入式
刘航宇
3年前
0
920
13
2022-01-29
【9】基于STM32CubeMX-STM32OLED开发
目录 必备文件 关于OLED的概述 OLED开发相关资源下载 基于STM32CubeMX的OLED底层驱动函数移植 OLED驱动库中常用的函数 实训案例:STM32控制OLED显示 必备文件 OLED文件-SPI版 下载地址:https://wwu.lanzoub.com/iCqK302ybokh 提取码: OLED I2C版4脚 下载地址:https://wwi.lanzouw.com/ilMr9zjrhsb 提取码: 关于OLED的概述 OLED:Organic Light-Emitting Display,有机发光显示。 OLED具备自发光、厚度薄、视角广、功耗低、对比度高、响应速度快、可用于挠曲性面板、使用温度范围广、构造及其制作过程较简单等优异特性,并认为是一种比液晶显示更为先进的新一代平板显示技术。以目前的技术,OLED的尺寸还难以大型化,但是分辨率却可以做得很高。 基于STM32的OLED应用,要做那些事情: 【1】移植OLED的底层驱动函数库。 【2】准备需要的中文字符和图片等数据。 【3】调用OLED驱动库中的底层函数进行应用开发。 图片 OLED开发相关资源下载 基于STM32CubeMX的OLED屏驱动程序库(内含4个文件) 【1】XMF_OLED_STM32Cube.c:驱动程序的源文件。 【2】XMF_OLED_STM32Cube.h:驱动程序的头文件。 【3】XMF_OLED_Font.h:字库数据文件。 【4】XMF_OLED_BMP.h:图片数据文件。 基于STM32CubeMX的OLED底层驱动函数移植 【1】将4个驱动文件拷贝到工程文件中,和main.c放在同一目录,并将XMF_OLED_STM32Cube.c添加到工程代码文件中,并在main.c中引入头文件XMF_OLED_STM32Cube.h。 【2】根据所选用的芯片型号,修改XMF_OLED_STM32Cube.h头文件中所以用的芯片头文件。 【3】根据硬件电路原理图中,修改XMF_OLED_STM32Cube.h中OLED的引脚定义。 【4】查看OLED_Init(void)初始化函数的源码,根据电路接口和应用需要进行修改。 图片 OLED驱动库中常用的函数 void OLED_Init(void); //OLED初始化函数 void OLED_Clear(void); //OLED清屏函数//显示英文字符串函数 void OLED_ShowString(unsigned char x,unsigned char y,unsigned char *p); 参数1:x,起点列坐标,0~127 参数2:y,起点行坐标,0~7 参数3:*p,字符串指针 返回值:void,无。//显示中文字符函数 void OLED_ShowCHinese(unsigned char x,unsigned char y,unsigned char no); 参数1:x,起点列坐标,0~127 参数2:y,起点行坐标,0~7 参数3:no,待显示中文字符在数组Hzk[][32]中的位置。 返回值:void,无。//显示图片函数 void OLED_DrawBMP( unsigned char x0, unsigned char y0,unsigned char x1,unsigned char y1,unsigned char BMP[]); 参数1:x0,起点列坐标,0~127 参数2:y0,起点行坐标,0~7 参数3:x1,图片的列范围,1~128 参数4:y1,图片的行范围,1~8 参数5:BMP[],待显示图片数据的数组。 返回值:void,无。实训案例:STM32控制OLED显示 要点 图片 字库软件中行前后缀不需要括号 在XMF07A或XMF07C开发板上,利用STM32CubeMX和Keil5协同开发,完成以下的功能: 【1】用取字模软件生产一张图片数据,作为开机界面在OLED上显示。 【2】0.5秒后进入信息界面, 第1行显示网址“sciarm.com”, 第2行显示中文“小蜜蜂笔记”,第3行显示日期“2022-02-18”。 图片 //用取字模软件生成开机LOGO图片数据,并拷贝到XMF_OLED_BMP.h的数组中。 const unsigned char BMP1[] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, //此处省略64×62个字节元素 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, };//用取字模软件生成所需中文字符数据,保持到XMF_OLED_Font.h中的Hzk[]数组。 const unsigned char Hzk[][32]={ {0x00,0x00,0x00,0xE0,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x20,0x40,0x80,0x00,0x00}, {0x08,0x04,0x03,0x00,0x00,0x40,0x80,0x7F,0x00,0x00,0x00,0x00,0x00,0x01,0x0E,0x00},/*"小",0*/ /* (16 X 16 , 宋体 )*/ {0x10,0x4C,0x24,0x04,0xF4,0x84,0x8D,0x56,0x44,0x24,0x14,0xC4,0x24,0x54,0x0C,0x00}, {0x00,0x41,0x5D,0x55,0x54,0x55,0x55,0x7F,0x55,0x55,0x55,0x55,0x7C,0xC0,0x00,0x00},/*"蜜",1*/ /* (16 X 16 , 宋体 )*/ {0x00,0xF8,0x08,0xFF,0x08,0xF8,0x80,0x90,0x4C,0x57,0xA4,0x54,0x4C,0x84,0x80,0x00}, {0x20,0x63,0x21,0x1F,0x11,0x39,0x10,0x10,0x15,0x15,0xFF,0x15,0x15,0x10,0x10,0x00},/*"蜂",2*/ /* (16 X 16 , 宋体 )*/ {0x10,0x08,0x44,0x47,0x4C,0x54,0x44,0xD4,0x28,0x27,0x24,0x2C,0x34,0x04,0x04,0x00}, {0x00,0x10,0x12,0x12,0x12,0x12,0x12,0x7F,0x89,0x89,0x89,0x89,0x89,0x88,0xF0,0x00},/*"笔",3*/ /* (16 X 16 , 宋体 )*/ {0x40,0x40,0x42,0xCC,0x00,0x00,0x00,0x84,0x84,0x84,0x84,0x84,0xFC,0x00,0x00,0x00}, {0x00,0x00,0x00,0x7F,0x20,0x10,0x00,0x3F,0x40,0x40,0x40,0x40,0x41,0x40,0x70,0x00},/*"记",4*/ /* (16 X 16 , 宋体 )*/ };extern unsigned char BMP1[]; void OLED_display_pic() { OLED_Clear(); OLED_DrawBMP(0,0,128,8,BMP1); }void OLED_display_info() { OLED_Clear(); OLED_ShowString(6,0,(uint8_t *)"sciarm.com"); OLED_ShowCHinese(10,3,0); //小 OLED_ShowCHinese(28,3,1); //蜜 OLED_ShowCHinese(46,3,2); //蜂 OLED_ShowCHinese(64,3,3); //笔 OLED_ShowCHinese(82,3,4); //记 OLED_ShowString(24,6,(uint8_t *)"2022-02-18"); }//在mian()函数中添加下面的代码: /* USER CODE BEGIN 2 */ OLED_Init(); //OLED初始化 OLED_display_pic(); //显示图片 HAL_Delay(500); //延时0.5秒 OLED_display_info(); //显示信息 /* USER CODE END 2 */
嵌入式&系统
# 嵌入式
刘航宇
3年前
17
1,606
14
2022-01-26
【8】基于STM32CubeMX-STM32ADC开发基础
目录 STM32的ADC资源概述 ADC启动与停止相关的HAL库函数 ADC转换结果读取的HAL库函数 查询方式,阻塞式A/D转换HAL库函数 中断方式,非阻塞式A/D转换HAL库函数 实训案例:ADC单次数据采样与电压换算用查询,阻塞的方式来实现 用中断,非阻塞的方式来实现 STM32的ADC资源概述 STM32F103ZE芯片(144脚)中有ADC1、ADC2、ADC3共3个12位逐次逼近型模数转换器,具有18个测量通道,可测量16个外部和2个内部信号源(内部温度和内部参考电压)。这2个内部信号源只能连接到ADC1。 ADC的各个通道的A/D转换可以单次、连续、扫描或间断模式执行。 A/D转换结果以左对齐或右对齐的方式,存储在16位规则组或者注入组数据寄存器中。 按照A/D转换的组织形式来划分,ADC的模拟输入通道分为规则组和注入组两种。 ADC可以对一组最多16个通道按照指定的顺序逐个进行转换,这组指定的通道称为规则组。 在实际应用中,可能需要中断规则组的转换,临时对某些通道进行转换,好像这些通道注入了原来的规则组,故称注入组,最多由4个通道组成。 ADC启动与停止相关的HAL库函数 //查询,阻塞方式,启动ADC HAL_StatusTypeDef HAL_ADC_Start(ADC_HandleTypeDef* hadc); //查询,阻塞方式,停止ADC HAL_StatusTypeDef HAL_ADC_Stop(ADC_HandleTypeDef* hadc); //中断,非阻塞方式,启动ADC HAL_StatusTypeDef HAL_ADC_Start_IT(ADC_HandleTypeDef* hadc); //中断,非阻塞方式,停止ADC HAL_StatusTypeDef HAL_ADC_Stop_IT(ADC_HandleTypeDef* hadc);ADC转换结果读取的HAL库函数 uint32_t HAL_ADC_GetValue(ADC_HandleTypeDef* hadc); 参数1:hadc,ADC实例指针。 返回值:uint32_t,ADC转换结果。查询方式,阻塞式A/D转换HAL库函数 HAL_StatusTypeDef HAL_ADC_PollForConversion(ADC_HandleTypeDef* hadc, uint32_t Timeout); 参数1:hadc,ADC实例指针。 参数2:Timeout,超时时间。 返回值:HAL_StatusTypeDef,函数执行状态。应用实例:用查询的方式,进行一次A/D采样并将结果读出。 uint16_t ADC_Value = 0; //以查询的方式启动ADC HAL_ADC_Start(&hadc); //等待一次规则组的ADC转换完成,并将结果读出 if(HAL_OK == HAL_ADC_PollForConversion(&hadc1,10)) { ADC0_Value = HAL_ADC_GetValue(&hadc1); }中断方式,非阻塞式A/D转换HAL库函数 应用实例:用中断的方式,进行一次A/D采样并将结果读出。 uint16_t ADC_Value = 0; //以中断的方式启动ADC HAL_ADC_Start_IT(&hadc); //重写ADC转换完成中断回调函数 void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) { ADC0_Value = HAL_ADC_GetValue(&hadc1); }实训案例:ADC单次数据采样与电压换算 在XMF07A或XMF07C开发板上,利用STM32CubeMX和Keil5协同开发,完成以下的功能: 【1】将ADC_IN0设置为12位ADC,右对齐,启用中断。 【2】分别用查询和中断这2种方式,每隔0.5秒采样一次ADC的数据。 【3】将每次读取到的ADC采样值转换为对应电压值,发送到上位机。 【4】LED1作为采样指示灯,在ADC转换过程中点亮,其余时间熄灭。 图片 要点配置 图片 图片 串口 图片 没有接收中断,不需要对NVIC进行使能 #include "stdio.h" #define LED1_ON() HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_SET) #define LED1_OFF() HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_RESET) uint16_t ADC0_Value = 0, ADC0_Volt = 0; uint8_t str_buff[64];void UR1_Send_Info() { sprintf((char *)str_buff,"采样值:%d,电压值:%d.%d%dV\r\n",ADC0_Value,ADC0_Volt/100,(ADC0_Volt%100)/10,ADC0_Volt%10); HAL_UART_Transmit(&huart1,str_buff,sizeof(str_buff),10000); }用查询,阻塞的方式来实现 void Get_ADC_Value() { HAL_ADC_Start(&hadc1); LED1_ON(); if(HAL_OK == HAL_ADC_PollForConversion(&hadc1,10)) { ADC0_Value = HAL_ADC_GetValue(&hadc1); ADC0_Volt = ADC0_Value * 330 / 4096; } UR1_Send_Info(); LED1_OFF(); HAL_ADC_Stop(&hadc1); }//在mian()函数中添加以下代码: /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { Get_ADC_Value(); //启动一个阻塞式的ADC转换并读取数据 // UR1_Send_Info(); //向上位机发生采样值和电压值 HAL_Delay(500); //延时0.5秒,再进行下一次ADC采样 /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */用中断,非阻塞的方式来实现 void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) { if(hadc->Instance == ADC1) { ADC0_Value = HAL_ADC_GetValue(&hadc1); //读取ADC转换结果 ADC0_Volt = ADC0_Value * 330 / 4096; //将采样值换算成电压值 UR1_Send_Info(); //向上位机发生ADC采样信息 LED1_OFF(); //关闭LED1采样指示灯 } }//在mian()函数中添加以下代码: /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { HAL_ADC_Start_IT(&hadc1); //启动一个非阻塞式的ADC转换并读取数据 LED1_ON(); //点亮LED1采样指示灯 HAL_Delay(500); //延时0.5秒,再进行下一次ADC采样 /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */
嵌入式&系统
# 嵌入式
刘航宇
3年前
1
1,153
11
【7】基于STM32CubeMX-STM32ADC模数转化基本原理
目录 模数转换器(ADC)概述 ADC的几个技术指标 剖析ADC的基本转换过程 实训案例:ADC数据采样的计算应用 模数转换器(ADC)概述 ADC:Analog-to-Digital Converter 将时间和幅值连续的模拟量转化为时间和幅值离散的数字量,A/D转换一般要经过采样、保持、量化和编码4个过程。 常用ADC:逐次逼近型、双积分型、∑-Δ型。 图片 ADC的几个技术指标 【1】量程:指ADC所能输入模拟信号的类型和电压范围,即参考电压。信号类型包括单极性和双极性。 【2】转换位数:量化过程中的量化位数n。 A/D转换后的输出结果用n位二进制数来表示。 【例】:10位ADC的输出值就是0~1023。 【3】分辨率:ADC能够分辨的模拟信号最小变化量。计算公式是,分辨率 = 量程 / 2的n次方 【例】:量程为单极性0-5V,8位ADC的分辨率是,5 / 256 = 0.0195V 【4】转换时间:ADC完成一次完整的A/D转换所需要的时间,包括采样、保持、量化、编码的全过程。 剖析ADC的基本转换过程 图片 实训案例:ADC数据采样的计算应用 有一个温度测控系统,已知温度传感器在0到100度之间为线性输出,参考电压为5V,采用8为的A/D转换器,0度的时候,测的电压为1.8伏,100度的时候,测的电压为4.3伏。 【问题1】:系统的分辨率是多少? 【问题2】:采集到数据10010001,表示多大电压?温度是多少? 由于温度是线性变化,先求得斜率k,得到温度和电压的关系表达式。 k = (100 – 0)/(4.3-1.8) = 40, y = 40*(x-1.8) (x为采样得到的电压) 由于采用的是8为ADC,参考电压为5V,所以分辨率为: 5 / 256 = 0.0195V = 19.5mV(最小能分辨的电压,分辨率) 0.0195 * 40 = 0.78度(最小能分辨的温度) 因为 10010001B = 91H = 145(16x9+1), 所以 0.0195 * 145 = 2.8275V 该电压信号对应的温度是:(2.83V – 1.8V) * 40 = 41.1摄氏度
嵌入式&系统
# 嵌入式
刘航宇
3年前
0
756
14
2022-01-23
【6】基于STM32CubeMX-STM32定时器与串口综合训练
目录 关于sprintf()函数的用法 实训案例:定时器与串口综合训练 关于sprintf()函数的用法 sprintf(),指的是字符串格式化函数,把格式化的数据写入某个字符串中。 int sprintf(char string, char format [,argument,…]); 引入头文件 #include “stdio.h“ 【例】:有一个表示温度的整型变量tmp,现在要将其格式化为字符串“温度是:XX摄氏度”,并将其通过串口1发送出去。 #include "stdio.h" uint8_t Str_buff[64]; sprintf((char*)Str_buff, "温度是: %d摄氏度", tmp); HAL_UART_Transmit(&huart1, Str_buff, sizeof(Str_buff), 0xFFFF);实训案例:定时器与串口综合训练 配置要点 时钟 图片 图片 外设 图片 图片 在XMF07A或XMF07C开发板上,利用STM32CubeMX和Keil5协同开发,完成以下的功能: 【1】开机后,LED1与LED2依次点亮,然后熄灭,进行灯光检测,高电平点亮LED灯。 【2】系统通过串口1向上位机发送一个字符串“=========XMF07欢迎你!==========”。 【3】LED1作为一个秒闪灯,系统向上位机发送完字符串后,开始亮0.5 秒,灭0.5秒….循环闪烁,并启动系统运行时间的记录,其时分秒格式为 “XX:XX:XX”。 【4】上位机通过一个由3个字节组成的命令帧控制LED2灯的开关。 该命令帧的格式为 “0xBF 控制字 0xFB”。 0xBF为帧头,0xFB为帧尾,控制字的定义如下: 0xA1:打开LED2,返回信息 “XX:XX:XX LED2打开。” 0xA2:关闭LED2,返回信息 “XX:XX:XX LED2关闭。” 其他:返回信息 “XX:XX:XX 这个一个错误指令!”。 #define LED1_ON() HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_SET) #define LED2_ON() HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_SET) #define LED1_OFF() HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_RESET) #define LED2_OFF() HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_RESET) #define LED1_TOG() HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_9) #define LED2_TOG() HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_8) uint8_t str1[] = "===============XMF07欢迎你!================\r\n"; uint8_t hh = 0, mm = 0, ss = 0, ss05 = 0; uint8_t str_buff[64]; uint8_t Rx_dat[16];void Ckeck_LED() { LED1_ON(); HAL_Delay(500); LED2_ON(); HAL_Delay(500); LED1_OFF(); HAL_Delay(500); LED2_OFF(); HAL_Delay(500); }void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { LED1_TOG(); ss05++; if(ss05 == 2) { ss05 = 0; ss++; if(ss == 60) { ss = 0; mm++; if(mm == 60) { mm = 0; hh++; } } } }void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if(huart->Instance == USART1) { if(Rx_dat[0] == 0xBF && Rx_dat[2] == 0xFB) { switch(Rx_dat[1]) { case 0xa1: LED2_ON(); sprintf((char *)str_buff,"%d:%d:%d LED2打开!\r\n",hh,mm,ss); break; case 0xa2: LED2_OFF(); sprintf((char *)str_buff,"%d:%d:%d LED2关闭!\r\n",hh,mm,ss); break; default: sprintf((char *)str_buff,"%d:%d:%d 这是一个错误的命令!\r\n",hh,mm,ss); break; } HAL_UART_Transmit(&huart1,str_buff,sizeof(str_buff),10000); HAL_UART_Receive_IT(&huart1,Rx_dat,3); } } }//在mian()函数中添加以下代码: Ckeck_LED(); //LED灯流水检测 HAL_UART_Transmit(&huart1,str1,sizeof(str1),0xFFFF); //向上位机发送欢迎字符 HAL_UART_Receive_IT(&huart1,Rx_dat,3); //启动串口1接收上位机3个字节 HAL_TIM_Base_Start_IT(&htim2); //启动定时器TIM2
嵌入式&系统
# 嵌入式
刘航宇
3年前
0
838
11
上一页
1
...
12
13
14
...
26
下一页