🌍首页
📁归档
⏳时光机
🚩友链
📫留言
📧订阅
🌟推荐
📕考研课程
🏜️ 免费壁纸
❤ 捐助本站
💰资助名单
🎵音乐实验
Search
1
【NPN/PNP三极管】放大电路饱和失真和截止失真的区别
20,264 阅读
2
论文写作中如何把word/wps里面所有数字和字母替换为新罗马字体
10,790 阅读
3
【高数】形心计算公式讲解大全
9,138 阅读
4
Vivado-FPGA Verilog烧写固化教程
8,204 阅读
5
【概论】一阶矩、二阶矩原点矩,中心矩区别与概念
7,923 阅读
🪶微语&随笔
励志美文
我的随笔
工作办公
📡电子&通信
嵌入式&系统
通信&信息处理
编程&脚本笔记
⌨️IC&系统
FPGA&ASIC
VLSI&IC验证
EDA&虚拟机
💻电子&计算机
IP&SOC设计
机器学习
软硬件算法
登录
/
注册
ed(共165篇)
找到
165
篇与
ed
相关的结果
- 第 10 页
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
励志美文
刘航宇
4年前
0
450
3
HAL_STM32_DS18B20开发
摘要本文介绍了如何使用HAL_STM32库和DS18B20温度传感器进行温度测量。文章详细说明了如何设置接口、初始化传感器、读取温度数据,并提供了相应的C语言代码示例。关键词: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();进行调用数值,可见精度达到要求了 图片 图片
嵌入式&系统
刘航宇
4年前
4
1,588
12
2022-01-31
【10】基于STM32CubeMX-STM32ADC与OLED开发
摘要本文介绍了在XMF07A或XMF07C开发板上,使用STM32CubeMX和Keil5开发环境,实现ADC与OLED综合训练的过程。通过OLED显示图片、灯光检测、数据采集和显示等功能,展示了STM32CubeMX和OLED的协同工作。关键词: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 */
嵌入式&系统
# 嵌入式
刘航宇
4年前
0
1,110
13
2022-01-29
【9】基于STM32CubeMX-STM32OLED开发
摘要本文介绍了基于STM32CubeMX-STM32OLED的开发过程,包括OLED概述、驱动函数库移植、常用函数介绍以及实训案例,展示了如何使用STM32控制OLED显示图片和信息。关键词:STM32CubeMX, OLED, STM32, 驱动程序, 显示开发目录 必备文件 关于OLED的概述 OLED开发相关资源下载 基于STM32CubeMX的OLED底层驱动函数移植 OLED驱动库中常用的函数 实训案例:STM32控制OLED显示 必备文件 必备文件 见文章末尾 关于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_Initvoidvoidvoid初始化函数的源码,根据电路接口和应用需要进行修改。 图片 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 */必备文件
嵌入式&系统
# 嵌入式
刘航宇
4年前
17
2,160
15
2022-01-26
【8】基于STM32CubeMX-STM32ADC开发基础
摘要本文介绍了STM32CubeMX-STM32ADC开发基础,包括STM32F103ZE芯片的ADC资源概述、启动与停止相关的HAL库函数、ADC转换结果读取的HAL库函数,以及查询方式、阻塞式和非阻塞式A/D转换的HAL库函数。通过实训案例,展示了如何使用STM32CubeMX和Keil5进行ADC单次数据采样与电压换算。关键词:STM32CubeMX, STM32ADC, 模数转换器, ADC转换, 电压换算目录 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 */
嵌入式&系统
# 嵌入式
刘航宇
4年前
1
1,592
11
2022-01-23
【6】基于STM32CubeMX-STM32定时器与串口综合训练
摘要本文介绍了STM32CubeMX和Keil5环境下,利用STM32定时器和串口实现LED灯控制及时间显示的实训案例。通过配置时钟、外设,实现LED灯流水检测、串口发送欢迎信息、LED1秒闪灯和LED2远程控制等功能。关键词:STM32CubeMX, STM32定时器, 串口通信, 字符串格式化, LED控制目录 关于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
嵌入式&系统
# 嵌入式
刘航宇
4年前
0
1,084
11
2022-01-21
【5】基于STM32CubeMX-STM32串口数据收发
摘要本文介绍了STM32CubeMX-STM32串口数据收发相关知识,包括串行通信概念、STM32串口USART功能、HAL库中串口发送和接收函数,并通过一个实训案例展示了如何通过串口控制LED灯开关。关键词:STM32CubeMX, STM32串口, 数据收发, HAL库函数, 串口通信目录 串行接口相关知识点 HAL库中串口发送的重要函数 HAL库中串口接收的重要函数 实训案例:上位机通过串口控制LED灯开关 串行接口相关知识点 并行通信、串行通信的概念。 单工、半双工、全双工的概念。 异步串行通信:通信双方在没有同步时钟的前提下,将一个字符(包括特定的附加位)按位进行传输的通信方式。 波特率:每秒钟传输的二进制位数,如9600bps。 TTL电平<—->RS232:MAX3232 SP3232 串口<———>USB接口:CH340 CP2012 STM32芯片的串口UASRT功能十分强大,但对于日常编程而言,使用最多的还是异步串行通信。 串口1:USART1_TX与PA9复用,USART1_RX与PA10复用。 串口2:USART2_TX与PA2复用,USART2_RX与PA3复用。 HAL库中串口发送的重要函数 ////查询方式,阻塞式发送函数(初学者,推荐使用) HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart,uint8_t *pData,uint16_t Size, uint32_t Timeout); 参数1:huart,串口实例的指针。 参数2:*pData,待发送数据缓冲区的指针。 参数3:Size,待发送数据的字节数。 参数4:Timeout,超时时间值。 返回值:HAL_StatusTypeDef,函数执行状态。 typedef enum { HAL_OK = 0x00U, HAL_ERROR = 0x01U, HAL_BUSY = 0x02U, HAL_TIMEOUT = 0x03U } HAL_StatusTypeDef; ////中断方式,非阻塞式发送函数 HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart,uint8_t *pData, uint16_t Size); 参数1:huart,串口实例的指针。 参数2:*pData,待发送数据缓冲区的指针。 参数3:Size,待发送数据的字节数。 返回值:HAL_StatusTypeDef,函数执行状态。 ////串口发送完毕中断回调函数 void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart); void HAL_UART_TxHalfCpltCallback(UART_HandleTypeDef *huart)应用举例:使用非阻塞式的串口发送函数,将发送缓数组dat_Txd中的前5个数据发送到USART1,在数据发送完成后,翻转PB9引脚的输出电平。 //使用中断,非阻塞方式 HAL_UART_Transmit_IT(&huart1, dat_Txd, 5); void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) { if(huart->Instance == USART1); { HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_9); } } //使用查询,阻塞方式 HAL_UART_Transmit(&huart1, dat_Txd, 5, 10000); HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_9);HAL库中串口接收的重要函数 ////查询方式,阻塞式接收函数 HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout); 参数1:huart,串口实例的指针。 参数2:*pData,数据接收据缓冲区的指针。 参数3:Size,待接收数据的字节数。 参数4:Timeout,超时时间值。 返回值:HAL_StatusTypeDef,函数执行状态。 非阻塞式接收函数(推荐使用) HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart,uint8_t *pData,uint16_t Size); 参数1:huart,串口实例的指针。 参数2:*pData,数据接收据缓冲区的指针。 参数3:Size,待接收数据的字节数。 返回值:HAL_StatusTypeDef,函数执行状态。 ////串口接收完毕中断回调函数 void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart); void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart);应用举例:使用非阻塞式的串口接收函数,接收USART1中的一个字节,将其保存在dat_Rxd变量中,在数据接收完成后,判断该字节,若为0x5A,则翻转PB8引脚的输出电平。 //使用中断,非阻塞方式 HAL_UART_Transmit_IT(&huart1, &dat_Rxd, 1); void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if(huart->Instance == USART1) { if(dat_Rxd == 0x5A) HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_8); } }实训案例:上位机通过串口控制LED灯开关 调试要点: 图片 在XMF07A或XMF07C开发板上,利用STM32CubeMX和Keil5协同开发,完成以下的功能: 【1】开机后,向串口1发送“hello world!”。 【2】串口1收到字节指令“0xA1”,打开LED1,发送“LED1 Open!”。 【3】串口1收到字节指令“0xA2”,关闭LED1,发送“LED1 Closed!”。 【4】在串口发送过程中,打开LED2作为发送数据指示灯。 图片 #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) #define LED2_ON() HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_SET) #define LED2_OFF() HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_RESET) uint8_t Tx_str1[] = "hello world!\r\n"; uint8_t Tx_str2[] = "LED1 Open!\r\n"; uint8_t Tx_str3[] = "LED1 Closed!\r\n"; uint8_t Rx_dat = 0;void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if(huart->Instance == USART1) { if(Rx_dat == 0xa1) { LED1_ON(); LED2_ON(); HAL_UART_Transmit(&huart1,Tx_str2,sizeof(Tx_str2),10000); LED2_OFF(); HAL_UART_Receive_IT(&huart1,&Rx_dat,1); } else if(Rx_dat == 0xa2) { LED1_OFF(); LED2_ON(); HAL_UART_Transmit(&huart1,Tx_str3,sizeof(Tx_str3),10000); LED2_OFF(); HAL_UART_Receive_IT(&huart1,&Rx_dat,1); } } }//在mian()函数中添加以下代码: LED2_ON(); HAL_UART_Transmit(&huart1,Tx_str1,sizeof(Tx_str1),10000); //向上位机发送“hello world!” LED2_OFF(); HAL_UART_Receive_IT(&huart1,&Rx_dat,1); //启动串口1接收上位机1个字节
嵌入式&系统
# 嵌入式
刘航宇
4年前
2
1,751
19
【4】基于STM32CubeMX-STM32定时器开发
摘要本文介绍了STM32CubeMX-STM32定时器开发,包括定时器基本原理、STM32定时器资源、通用定时器结构和工作原理,并通过实训案例展示了如何利用TIM2和TIM3定时器控制LED灯的开关状态。关键词:STM32CubeMX, STM32定时器, 通用定时器, 定时器中断, LED控制目录 定时器的基本概述 STM32通用定时器的重要知识点 实训案例:外部中断信号控制LED灯开关 定时器的基本概述 通过滴漏和漏沙瓶这两个例子简单讲述定时器的基本工作原理。 STM32的常见的定时器资源: 系统嘀嗒定时器SysTick、看门狗定时器WatchDog、实时时钟RTC、基本定时器、通用定时器、高级定时器。 系统嘀嗒定时器SysTick :这是一个集成在Cortex M3内核当中的定时器,它并不属于芯片厂商的外设,也就是说使用ARM内核的不同厂商,都拥有基本结构相同的系统定时器。主要目的是给RTOS提供时钟节拍做时间基准。 基本定时器:TIM6、TIM7。 通用定时器:TIM2、TIM3、TIM4、TIM5。在基本定时器的基础上,实现输出比较、输入捕获、PWM生成、单脉冲模式输出等功能。这类定时器最具代表性,使用也最广泛。 高级定时器:TIM1、TIM8。 STM32通用定时器的重要知识点 通用定时器的基本结构组成: STM32的通用定时器,是一个通过可编程预分频器(Prescaler)驱动的16位自动重装主计数器(Counter Period)构成。可以对内部时钟或触发源以及外部时钟或触发源进行计数。 通用定时器的基本工作原理: 首先,定时器时钟信号送入16位可编程预分配器(Prescaler),该预分配器系数为0~65535之间的任意数值。预分配器溢出后,会向16位的主计数器(Counter Period)发出一个脉冲信号。 预分频器,本质上是一个加法计数器,预分频系数实际上就是加计数的溢出值。 定时器发生中断时间的计算方法: 定时时间 = (Prescaler+1 ) X (Counter Period+1) X 1/ 定时器时钟频率 时钟信号1KHz,Prescaler为9,Counter Period为999,定时时间? 图片 计算案例 图片 实训案例:外部中断信号控制LED灯开关 配置要点 图片 图片 图片 图片 图片 图片 图片 图片 在XMF07A或XMF07C开发板上,利用STM32CubeMX和Keil5协同开发,完成以下的功能: 【1】利用TIM2实现间隔定时,每隔0.2秒将LED1的开关状态翻转。 【2】利用TIM3实现间隔定时,每隔1秒将LED2的开关状态翻转。 【3】修改TIM2的初始化代码,改为每隔0.5秒将LED1的开关状态翻转。 图片 /* USER CODE BEGIN 0 */ void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if(htim->Instance == TIM2) //处理TIM2间隔定时中断 { AL_GPIO_TogglePin(GPIOB,GPIO_PIN_9); } if(htim->Instance == TIM3) //处理TIM3间隔定时中断 { HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_8); } } /* USER CODE END 0 *//* USER CODE BEGIN 2 */ HAL_TIM_Base_Start_IT(&htim2); //启动定时器TIM2 HAL_TIM_Base_Start_IT(&htim3); //启动定时器TIM3 //有IT的代表使能时钟中断 /* USER CODE END 2 */
嵌入式&系统
# 嵌入式
刘航宇
4年前
2
1,483
26
2022-01-17
【3】基于STM32CubeMX-STM32中断系统
摘要本文介绍了STM32中断系统,包括中断概念、STM32中断源、中断向量、中断优先级等基础概念,并详细阐述了STM32外部中断的设计步骤和程序编写方法,最后通过实训案例展示了如何利用STM32CubeMX和Keil5实现外部中断控制LED灯开关。关键词:STM32CubeMX, STM32中断系统, 外部中断, NVIC, GPIO中断目录 中断什么意思 STM32的中断系统 STM32的外部中断 外部中断的程序设计思路 外部中断初始化函数剖析 外部中断服务函数的编写 实训案例:外部中断信号控制LED灯开关 中断什么意思 你打开火,烧上一壶水。然后去洗衣服,在洗衣服的过程中,突然听到水壶发出水开的报警声,这时,你停止洗衣服动作,立即去关掉火,然后将开水灌入暖水瓶中,灌完开水后,你又回去继续洗衣服。这个过程中实际上就发生了一次中断。 如图: 图片 图片 STM32的中断系统 理解中断、中断源、中断向量、中断优先级、中断服务函数…等基础概念。 ARM Cortex M3内核支持256个中断,包括16个内核中断和240个外设中断,拥有256个中断优先级别。 STM32的中断通道可能会由多个中断源共用。这就意味着,某一个中断服务函数也可能被多个中断源所共用。所以,在中断服务函数的入口处,需要有一个判断机制,用以辨别是那个中断触发了中断。 STM32微处理器的内核中有一个NVIC(嵌套向量中断控制器)的设备,它对中断进行统一的协调和控制,其中最主要的工作就是控制中断通道的使能和确定中断的优先级。 STM32中有2个优先级的概念:抢占优先级和响应优先级,每个中断都需要指定这两种优先级。 如果两个抢占优先级相同的中断同时到达,NVIC会根据他们的响应优先级高低来决定先处理哪一个。如果两个同时到达的中断的抢占优先级和响应优先级都相等,则根据中断的自然排位顺序来决定响应哪一个。 STM32的外部中断 外部中断EXTI是STM32微处理器实时处理外部事件的一种机制,由于中断请求主要来自GPIO端口的引脚,所以称为外部中断。 STM32F013微处理器有19个能产生事件/中断请求的边沿检测器,每个输入线可以独立地配置成输入类型(脉冲或挂起)和对应的触发事件(上升沿、下降沿或双边沿触发),也可以独立地屏蔽。 EXTI0~EXTI15:GPIO端口引脚。 EXTI16:PVD输出,可编程电压监测。 EXTI17:RTC闹钟。 EXTI18:USB唤醒。 外部中断的程序设计思路 传统STM32外部中断设计步骤 : 【1】将GPIO初始化为输入端口。 【2】配置相关I/O引脚与中断线的映射关系。 【3】设置该I/O引脚对应的中断触发条件。 【4】配置NVIC,并使能中断。 【5】编写中断服务函数。 配置要点提示 引脚设外部中断,上升沿,上拉 图片 使能NVIC 图片 基于STM32CubeMX的外部中断设计步骤: 【1】在STM32CubeMX中指定引脚,配置中断初始化参数。 选择GPIO引脚的功能,设置中断信号触发条件,使能NVIC对应的中断通道。 【2】重写该I/O引脚对应的中断回调函数。 外部中断初始化函数剖析 //外部中断初始化相关的操作在gpio.c文件中的MX_GPIO_Init()函数完成。 void MX_GPIO_Init(void) { /*===================== 此处省略无关代码。 ======================*/ /* EXTI interrupt init 外部中断初始化*/ HAL_NVIC_SetPriority(EXTI9_5_IRQn, 0, 0); //设置EXIT9~EXIT5中断的优先级 HAL_NVIC_EnableIRQ(EXTI9_5_IRQn); //使能EXIT9~EXIT5中断通道 HAL_NVIC_SetPriority(EXTI15_10_IRQn, 0, 0); HAL_NVIC_EnableIRQ(EXTI15_10_IRQn); }外部中断服务函数的编写 图片 实训案例:外部中断信号控制LED灯开关 在XMF07A或XMF07C开发板上, 利用STM32CubeMX和Keil5协同开发, 完成以下的功能: 【1】将KEY2,即PC13设置为外部中断输入,下降沿触发。在中断服务函数中,切换LED1的开关状态。 【2】将KEY4,即PB5设置为外部中断输入,上升沿触发。在中断服务函 数中,切换LED2的开关状态。 图片 //外部中断的初始化函数由STM32CubeMX辅助生成,用户只需要重写中断回调函数。 /* USER CODE BEGIN 0 */ void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { if(GPIO_Pin == GPIO_PIN_13) { HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_9); } if(GPIO_Pin == GPIO_PIN_5) { HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_8); } } /* USER CODE END 0 */
嵌入式&系统
# 嵌入式
刘航宇
4年前
0
1,253
16
2022-01-17
【2】基于STM32CubeMX-STM32按键开发
摘要本文介绍了基于STM32CubeMX的按键扫描原理,包括按键信号识别、去抖动处理和GPIO输入电平读取。通过HAL库函数实现按键控制LED灯的开关,包括按键配置、去抖动处理和按键扫描函数。关键词:STM32CubeMX, STM32按键, 按键扫描, GPIO输入电平读取, LED灯控制目录 按键扫描的基本原理 GPIO输入电平读取HAL库函数 实训案例:按键控制LED灯开关 按键扫描的基本原理 按键信号是如何识别的? 一般来说,按键的两个引脚的一端通过电阻上拉到高电平,另一端则接地。 在没有按键按下的时候,输入引脚为高电平,当有按键按下,输入引脚则为低电平。通过反复读取按键输入引脚的信号,然后识别高低电平来判断是否有按键触发。 为什么去抖动? 按键的输入引脚有低电平产生不代表一定是有按键按下,也许是干扰信号 , 因此,需要通过去抖动处理,将这些干扰信号过滤,从而获得真实的按键触发信号。 如何去抖动? 首次检测到按键输入引脚有低电平后,稍作延时,再次读取该引脚,如还是低电平,则确认为按键触发信号;否则,判断为干扰信号,不予处理。 GPIO输入电平读取HAL库函数 GPIO_PinState HAL_GPIO_ReadPin( GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); 参数1:GPIOx,端口号,如:GPIOB,GPIOF。 参数2:GPIO_Pin,引脚号,如:GPIO_PIN_9,GPIO_PIN_12。 返回值:GPIO_PinState,引脚的电平状态。 应用举例:判断PC13引脚的输入信号,若为高电平,则将PB9引脚控制的LED灯的开关状态切换。 if(HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13) == GPIO_PIN_SET) { HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_9); }实训案例:按键控制LED灯开关 要点提示配置输入引脚时候注意是否存在上拉 图片 在XMF07A或XMF07C开发板上, 利用STM32CubeMX和Keil5协同开发, 完成以下的功能: 【1】按下KEY2按键,切换LED1的开关状态。 【2】按下KEY3按键,松开后,切换LED2的开关状态。 【3】按下KEY4按键,把点亮的LED灯全部关闭。 图片 #define KEY2 HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_13) #define KEY3 HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1) #define KEY4 HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_5)void Scan_Keys() { if(KEY2 == GPIO_PIN_RESET) { HAL_Delay(5); if(KEY2 == GPIO_PIN_RESET) { HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_9); while(KEY2 == GPIO_PIN_RESET); } } if(KEY3 == RESET) { HAL_Delay(5); if(KEY3 == RESET) { while(KEY3 == RESET); HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_8); } } if(KEY4 == 0) { HAL_Delay(5); if(KEY4 == 0) { HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9|GPIO_PIN_8,GPIO_PIN_RESET); while(KEY2 == 0); } } }/* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { Scan_Keys(); /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */
嵌入式&系统
# 嵌入式
刘航宇
4年前
9
2,645
91
2022-01-16
【1】基于STM32CubeMX-STM32GPIO端口开发
摘要本文介绍了STM32CubeMX代码辅助生成工具,讲解了STM32的GPIO端口知识、HAL库函数以及跑马灯实训案例。通过STM32CubeMX配置GPIO端口,实现LED灯的闪烁,并进行了仿真开发。关键词:STM32CubeMX, STM32GPIO, GPIO端口, HAL库函数, 跑马灯目录 STM32CubeMX的声明 protuesSTM32仿真开发板下载 STM32的GPIO端口知识要点 GPIO电平输出HAL库函数 GPIO电平翻转HAL库函数 GPIO初始化函数源码剖析 实训案例:基于STM32CubeMX的跑马灯 仿真开发实例 protuesSTM32仿真开发板下载 STM32CubeMX的声明 【1】STM32CubeMX 是一个代码辅助生成工具,在生成工程代码的同时,根据你的功能选择和配置帮你做了必要的初始化,这也就意味着你不再需要对底层的特殊功能寄存器进行初 始化配置,但是不代表你就可以不去学习 STM32 的基本知识和各个外设的工作原理与参数 特性等。 【2】虽然不再要求你去了解 STM32 底层寄存器的定义,但却要求你要了解由 STM32CubeMX生产的代码内在的逻辑联系以及 HAL 库中的常用函数原型与使用。 【3】STM32CubeMX 的最大好处就是,使开发流程、文件结构、库函数等标准化 protuesSTM32仿真开发板下载 下载方式见文章末尾 STM32的GPIO端口知识要点 GPIO:General Purpose Input & Output STM32芯片最拥有GPIOA、GPIOB…GPIOG等7组端口,每组端口最多拥有Pin0、Pin1…Pin15共16个引脚。 STM32的每个I/O端口都可以自由编程,但I/O端口寄存器必须按32位字被访问。STM32的每个I/O端口都由7个寄存器来控制。 STM32的GPIO端口可以由软件配置成8种模式: 推挽输出、开漏输出、推挽式复用功能、开漏式复用功能; 模拟输入、浮空输入、下拉输入、上拉输入。 GPIO电平输出HAL库函数 void HAL_GPIO_WritePinGPIOTypeDef∗GPIOx,uint16tGPIOPin,GPIOPinStatePinStateGPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinStateGPIOTypeDef∗GPIOx,uint16tGPIOPin,GPIOPinStatePinState; 参数1:GPIOx,端口号,如:GPIOB,GPIOF。 参数2:GPIO_Pin,引脚号,如:GPIO_PIN_9,GPIO_PIN_12。 参数3:PinState,引脚输出状态。高电平----GPIO_PIN_SET;低电平----GPIO_PIN_RESET。 返回值:void,空。 应用举例:向PB8引脚输出高电平。 HAL_GPIO_WritePinGPIOB,GPIOPIN8,GPIOPINSETGPIOB, GPIO_PIN_8, GPIO_PIN_SETGPIOB,GPIOPIN8,GPIOPINSET;GPIO电平翻转HAL库函数 void HAL_GPIO_TogglePinGPIOTypeDef∗GPIOx,uint16tGPIOPinGPIO_TypeDef* GPIOx, uint16_t GPIO_PinGPIOTypeDef∗GPIOx,uint16tGPIOPin; 参数1:GPIOx,端口号,如:GPIOB,GPIOF。 参数2:GPIO_Pin,引脚号,如:GPIO_PIN_9,GPIO_PIN_12。 返回值:void,空。 应用举例:将PA3引脚输出电平翻转。 HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_3);GPIO初始化函数源码剖析 void MX_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; /* GPIO端口时钟使能 */ __HAL_RCC_GPIOC_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); /*配置GPIO端口引脚的初始化输出电平 */ HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8|GPIO_PIN_9, GPIO_PIN_RESET); /*配置GPIO端口输入引脚 : PC13 */ GPIO_InitStruct.Pin = GPIO_PIN_13; //GPIO端口的引脚号是:13 GPIO_InitStruct.Mode = GPIO_MODE_INPUT; //GPIO的模式是:输入 GPIO_InitStruct.Pull = GPIO_NOPULL; //没有上拉 HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); //将参数结构设置到GPIOC端口 /*配置GPIO端口输出引脚 : PB8 PB9 */ GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9; //GPIO端口的引脚号是:8和9 GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; //GPIO的模式是:输出 GPIO_InitStruct.Pull = GPIO_NOPULL; //没有上拉 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; //GPIO的输出速度是:非常低速 HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); //将参数结构设置到GPIOB端口 }实训案例:基于STM32CubeMX的跑马灯 在XMF07A或XMF07C开发板上,利用STM32CubeMX对STM32芯片的LED控制引脚进行配置并快速生产项目,在Keil5中进行代码编写,实现跑马灯功能,即:LED1灯亮,过一会,LED2灯亮,过一会,LED1灯熄灭,过一会,LED2灯熄灭….如此循环。 XMF07C开发板:STM32L151C8T6 (电路功能兼容物联网国赛设备) XMF07A开发板:STM32F103C8T6 图片 /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_SET); //向PB9输出高电平,点亮LED1灯 HAL_Delay(500); //延时500ms HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_SET); //向PB9输出低电平,熄灭LED1灯 HAL_Delay(500); //延时500ms HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_9); //用翻转电平的方式,实现LED1灯的点亮与熄灭 HAL_Delay(500); //延时500ms HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_8); //用翻转电平的方式,实现LED2灯的点亮与熄灭 HAL_Delay(500); //延时500ms /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */仿真开发实例 原理图: 图片 1.新建CubeMX工程 选择对应的MCU,在proteus8中支持STM32F103的几款muc,这里我们选择STM32R6 图片 设置下载方式 图片 配置LED灯的GPIO l1p0om1l.png图片 配置时钟树 l1p0ownv.png图片 选择keil5工程(或者其他工程) l1p0pb0l.png图片 勾选此处可以使得每个初始化的外设有独立的.c和.h l1p0ptxo.png图片 生成MDK工程 l1p0ro0x.png图片 添加LED闪烁的代码,并编译生成.hex文件 HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_5); HAL_Delay(0XFF)l1p0sq2c.png图片 将hex文件下载到proteus8中去 l1p0t26z.png图片 此时仿真会报错,原因是电源为接入,只需要将电源接入即可 l1p0tjr9.png图片 此处VDDA,VSSA分别加入到电网VCC与GND中,详细可以百度 l1p0tpli.png图片 最后,就可以看到有一个LED灯反复交替闪烁! l1p0u3mg.png图片 protuesSTM32仿真开发板下载
嵌入式&系统
# 嵌入式
刘航宇
4年前
8
7,132
120
嵌入式视频流知识点及代码解析-精简版
摘要本文介绍了嵌入式视频流处理相关知识,包括Live555、FFmpeg、SDL等库的使用,以及RTSP、YUV、TCP/UDP等概念。通过代码解析,展示了如何实现视频流的接收、解码和显示。关键词:嵌入式视频流, Live555, FFmpeg, SDL, RTSP目录 背景和意义 框架 代码及相关知识点 一、知识点篇 二、问答篇 三、代码篇RTSP程序要不要等待播放器器程序请求? 请你找出上述代码所在位置 live555(了解) SDL 背景和意义 (1)视频的带宽很大,存储,传输不便,故要压缩、解压 、播放。 (2)应用领域很广 ,交通,在线教育,播放器,自动驾驶。 框架 图片 下面这个图及其重要以及3个ip关系 abcde代表先后实现顺序注意观看!!! TO67M8.png图片 代码及相关知识点 一、知识点篇 Live 555: 是一个为流媒体提供解决方案的跨平台的C++开源项目,它实现了标准流媒体传输,对标准流媒体传输协议如RTP/RTCP、RTSP、SIP等的支持。Live555实现了对多种音视频编码格式的音视频数据的流化、接收和处理等支持,包括MPEG、H.263+、DV、JPEG视频和多种音频编码。同时由于良好的设计,Live555非常容易扩展对其他格式的支持。Live555已经被用于多款播放器的流媒体播放功能的实现,如VLC(VideoLan)、MPlayer。 在本次开发实践中主要用于接收海康威视摄像头的RTP数据包 并通过UDP网络进行转发给PC机。 FFmpeg: Fmpeg是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。采用LGPL或GPL许可证。它提供了录制、转换以及流化音视频的完整解决方案。它包含了非常先进的音频/视频编解码库libavcodec,为了保证高可移植性和编解码质量,libavcodec里很多code都是从头开发的。 FFmpeg在Linux平台下开发,但它同样也可以在其它操作系统环境中编译运行,包括Windows、Mac OS X等。项目的名称来自MPEG视频编码标准,前面的"FF"代表"Fast Forward"。 在本次开发实践中主要用于H264数据解码。 SDL: SDL(Simple DirectMedia Layer)是一套开放源代码的跨平台多媒体开发库,使用C语言写成。SDL提供了数种控制图像、声音、输出入的函数,让开发者只要用相同或是相似的代码就可以开发出跨多个平台(Linux、Windows、Mac OS X等)的应用软件。目前SDL多用于开发游戏、模拟器、媒体播放器等多媒体应用领域。在本次开发实践中主要用于YUV数据的显示。 二、问答篇 1.什么是YUV?与RGB有什么不同? YUV 是一种颜色编码方法,FFmpeg 解码后的数据格式。Y 表示明亮度 U 表示色 度 V 表示浓度。因为通过研究发现,人类对于图像的感知中对明亮最侧重,色彩和 浓度就相对不那么重要,所以在保存图片时,让明亮度占较多的比重,有效的在不影 响观看的情况下节约了空间。视频播放器解码出来的格式为 YUV420P,其中明亮度 占整个数据的 2/3,色度和浓度占 1/3。 2.RTSP在什么层?答:应用层 3.你关于IP问题你用到了那些命令?答:ipconfig,ifconfig,ping等 4.本次课程设计你用到了那些去年学的知识?答:网络通信,文件开关与读写,第一章shell操作命令 下面部分自行百度: 5.TCP与UDP特点(TCP的可靠,UDP 的不可靠,UDP快) 6.简述TCP与UDP 7.了解HTTP/https 8.三次握手和四次挥手过程 三、代码篇 RTSP程序要不要等待播放器器程序请求? 答:要 请你找出上述代码所在位置 答:如图所示 图片 live555(了解) BasicTaskScheduler 的父类是BasicTaskScheduler0 BasicTaskScheduler0是一个用作传递的类,它继承自TaskScheduler,又派生出BasicTaskScheduler。其定义在live555sourcecontrol\UsageEnvironment\include\BasicUsageEnvironment0.hh文件中。 BasicTaskScheduler0中有 BasicTaskScheduler 这个类主要实现事件的处理 BasicUsageEnvironment 涉及调试语句,输出语句 ourRTSPClient 主要是涉及的数据的发送相关的功能函数,主要的功能继承于父类RTSPClient RequestRecord 创建一个请求记录对象,并将回调函数与之关联 sendRequest 第一次进入调用:openConnection解析URL,并调用setupStreamSocket和connectToServer,然后 envir().taskScheduler().setBackgroundHandling(fInputSocketNum, SOCKET_READABLE|SOCKET_EXCEPTION, (TaskScheduler::BackgroundHandlerProc*)&incomingDataHandler, this); 若不是第一次调用,则打包 RTSP 包协议,并调用 Send函数发送到服务器。 重点 RequestRecord入队列 等候读取数据。 setupStreamSocket调用createSocket ,createSocket调用: sock = socket(AF_INET, type, 0); connectToServer调用 connect(socketNum, (struct sockaddr*) &remoteName, sizeof remoteName) setBackgroundHandling 主要初始化select 函数的 文件描述符集合 incomingDataHandler 中包含函数 readSocket 调用 int bytesRead = recvfrom(socket, (char*)buffer, bufferSize, 0, (struct sockaddr*)&fromAddress, &addressSize);到此发送描述命令结束 ,等待响应服务器发送过来的数据。 incomingDataHandler1读取服务器的数据 incomingDataHandler1先调用readSocket调用,然后调用 handleResponseBytes 解析RTSP服务器数据 调用(*foundRequest->handler())(this, resultCode, resultString); 这个函数就是continueAfterDESCRIBE continueAfterDESCRIBE 调用下一步 setup 功能 SDL 抓1,2,3,4....等每段的关键句,可能考流程 rb为只读,对于不需要进行更新的文件,可以防止用户的错误的写回操作,防止损毁原有数据。具有较高的安全性。 rb+为更新二进制文件,可以读取,同时也可以写入,需要用到fseek之类的函数进行配合,以免出错,对于需要不时更新的文件,比如信息管理系统中的数据,可以这样打开。 初始化SDL 使用SDL_Init()初始化SDL。该函数可以确定希望激活的子系统。 int SDLCALL SDL_Init(Uint32 flags) SDL_INIT_VIDEO:视频 创建窗口(Window) 使用SDL_CreateWindow()创建一个用于视频播放的窗口。 SDL_Window SDLCALL SDL_CreateWindow(const char title,int x, int y, int w,int h, Uint32 flags); SDL_CreatWindow:第一个参数是窗口名字,第二三是窗口的坐标(SDL_winpos_undefined 为采用系统默认) title :窗口标题 x :窗口位置x坐标。也可以设置为SDL_WINDOWPOS_CENTERED或SDL_WINDOWPOS_UNDEFINED。 y :窗口位置y坐标。同上。 w :窗口的宽 h :窗口的高 flags :支持下列标识。包括了窗口的是否最大化、最小化,能否调整边界等等属性。 flags:SDL_WINDOW_RESIZABLE 自动调整窗口 基于窗口创建渲染器(Render) 使用SDL_CreateRenderer()基于窗口创建渲染器 SDL_Renderer SDLCALL SDL_CreateRenderer(SDL_Window window,int index, Uint32 flags); window: 渲染的目标窗口。 index:打算初始化的渲染设备的索引。设置“-1”则初始化默认的渲染设备。 SDL_RENDERER_PRESENTVSYNC:和显示器的刷新率同步 创建纹理(Texture) 使用SDL_CreateTexture()基于渲染器创建一个纹理 SDL_Texture SDLCALL SDL_CreateTexture(SDL_Renderer renderer,Uint32 format,int access, int w,int h); renderer:目标渲染器。 format:纹理的格式。 access:定义位于SDL_TextureAccess中 access:SDL_TEXTUREACCESS_STREAMING :变化频繁 w:纹理的宽 h:纹理的高 SDL_Thread *refresh_thread = SDL_CreateThread(RefreshVideo,NULL,NULL); //创建线程 SDL_Event event; //设置触发事件 6.在SDL中,当事件等待函数监听到事件后,判断事件类型,如果event.type == SDL_KEYDOWN,表明用户按下键盘,保存在event.key.keysym.sym是相应的键值。而根据键值,调用函数SDL_GetKeyName(event.key.keysym.sym)),即可得到按下的按键键名。 SDLK_RETURN == 13 回车! 7.读文件fread size_t fread(void buffer,size_t size,size_t count,FILE stream) buffer 是读取的数据存放的内存的指针(可以是数组,也可以是新开辟的空间,buffer就是一个索引) size 是每次读取的字节数 count 是读取次数 stream 是要读取的文件的指针 8.循环显示画面 (1)设置纹理的数据 使用SDL_UpdateTexture()设置纹理的像素数据 int SDLCALL SDL_UpdateTexture(SDL_Texture texture,const SDL_Rect rect,const void *pixels, int pitch); texture:目标纹理。 rect:更新像素的矩形区域。设置为NULL的时候更新整个区域。 pixels:像素数据。 pitch:一行像素数据的字节数。 (2)纹理复制给渲染目标 使用SDL_RenderCopy()将纹理数据复制给渲染目标。在使用SDL_RenderCopy()之前,可以使用SDL_RenderClear()先使用清空渲染目标。实际上视频播放的时候不使用SDL_RenderClear()也是可以的,因为视频的后一帧会完全覆盖前一帧 int SDLCALL SDL_RenderCopy(SDL_Renderer renderer,SDL_Texture texture,const SDL_Rect srcrect,const SDL_Rect dstrect); renderer:渲染目标。 texture:输入纹理。 srcrect:选择输入纹理的一块矩形区域作为输入。设置为NULL的时候整个纹理作为输入。 dstrect:选择渲染目标的一块矩形区域作为输出。设置为NULL的时候整个渲染目标作为输出。 (3) 显示 使用SDL_RenderPresent()显示画面 void SDLCALL SDL_RenderPresent(SDL_Renderer * renderer); 参数renderer用于指定渲染目标 9.退出 event.type==SDL_QUIT fclose(fp); //关闭文件! 防止遗留无用进程 SDL_DestroyTexture(texture); //关闭纹理 SDL_DestroyRenderer(renderer); //关闭渲染 SDL_DestroyWindow(window); //关闭窗口 SDL_Quit(); //退出线程 FFMPEG解码deco fun_deco_display.c 从void * deco_thread开始 play_ubuntu内 功能函数于主函数同时编译 多个c编译! gcc -o demo main.c fun_deco_display.c fun_others.c fun_recv_control.c -I /monchickey/ffmpeg/include -L /monchickey/ffmpeg/lib -lavformat -lavcodec -lavutil -lSDL2 -lpthread AVCodec codec; / 解码CODEC*/ AVCodecContext *cctx; AVFrame frame; / 解码后的图像*/ int byte_buffer_size; //解码器码流长度 uint8_t *byte_buffer = NULL; //h.264码流 AVPacket *pkt; //保存媒体流信息 AVPacket主要保存一些媒体流的基本信息,例如PTS、DTS时间。最重要的当然就是媒体数据的buffer地址了。 比较重要的有: pts:控制显示的pts时间 dts:控制解码的dts时间 *data:媒体数据buffer的指针 duration:AVStream-> time_base单位中此数据包的持续时间,如果未知则为0。 在演示顺序中等于next_pts - this_pts。 AVFormatContext主要存储视音频封装格式中包含的信息 解码前数据:AVPacket 解码后数据:AVFrame 1.AVFormatContext avformat_alloc_context(void)函数用来申请AVFormatContext类型变量并初始化默认参数。申请的空间通过void avformat_free_context(AVFormatContext s)函数释放。 2.avformat_find_stream_info()主要用于给每个媒体流(音频/视频)的AVStream结构体赋值,已经实现了解码器的查找,解码器的打开,视音频帧的读取,视音频帧的解码等工作 3.av_find_best_stream()函数就是要获取音视频对应的stream_index 获取流的索引 4.解码模块第一步:获取解码器 avcodec_find_decoder()FFmpeg的解码器编码器都存在avcodec的结构体中 5.avcodec_alloc_context3,avcodec_parameters_to_context,解码器初始化 6.avcodec_open2打开解码器 7.av_frame_alloc()首先调用av_mallocz()为AVFrame结构体分配内存 8.int av_image_get_buffer_size(enum AVPixelFormat pix_fmt, int width, int height, int align);函数的作用是通过指定像素格式、图像宽、图像高来计算所需的内存大小,av_malloc 按需分配空间 9.av_packet_alloc实际是分配AVPacket以后,调用av_init_packet对AVPacket的成员变量进行初始化赋值 10.av_read_frame()的作用是读取码流中的音频若干帧或者视频一帧 11.avcodec_send_packet()以在AVPacket中给出解码器原始的压缩数据 avcodec_receive_frame()。 成功后,它将返回一个包含未压缩音频或视频数据的 AVFrame 12. void av_image_copy_uc_from ( uint8_t * dst_data[4], const ptrdiff_t dst_linesizes[4], const uint8_t * src_data[4], const ptrdiff_t src_linesizes[4], enum AVPixelFormat pix_fmt, int width, int height ) 数据拷贝 13.av_packet_free(&pkt); //释放数据 关闭进程 av_frame_free(&frame); avformat_close_input(&fctx); avcodec_free_context(&cctx); avformat_free_context(fctx); Client && Server(了解) //Client_Upd 1.int socket(int domain, int type, int protocol); 函数socket()的参数domain用于设置网络通信的域,函数socket()根据这个参数选择通信协议的族 SOCK_DGRAM udp连接 socket()函数的原型如下,这个函数建立一个协议族为domain、协议类型为type、协议编号为protocol的套接字文件描述符。 2.memset可以方便的清空一个结构类型的变量或数组。初始化 3.family 通信协议的族 AF_INET,PF_INET IPv4 Internet协议 4.sockaddr_in在头文件#include<netinet/in.h>或#include <arpa/inet.h>中定义,该结构体解决了sockaddr的缺陷,把port和addr 分开储存在两个变量中。 htons()作用是将端口号由主机字节序转换为网络字节序的整数值。(host to net) inet_addr()作用是将一个IP字符串转化为一个网络字节序的整数值,用于sockaddr_in.sin_addr.s_addr。 5.在无连接的数据报socket方式下,由于本地socket并没有与远端机器建立连接,所以在发送数据时应指明目的地址,sendto()函数原型为: int sendto(int sockfd, const void msg,int len unsigned int flags, const struct sockaddr to, int tolen); 该函数比send()函数多了两个参数,to表示目地机的IP地址和端口号信息,而tolen常常被赋值为sizeof (struct sockaddr)。 int PASCAL FAR sendto( SOCKET s, const char FAR* buf, int len, int flags, const struct sockaddr FAR* to, int tolen); s:一个标识套接口的描述字。 buf:包含待发送数据的缓冲区。 len:buf缓冲区中数据的长度。 flags:调用方式标志位。 to:(可选)指针,指向目的套接口的地址。 tolen:to所指地址的长度 6.recvfrom()函数原型为: int recvfrom(int sockfd,void buf,int len,unsigned int lags,struct sockaddr from,int *fromlen); from是一个struct sockaddr类型的变量,该变量保存源机的IP地址及端口号。fromlen常置为sizeof (struct sockaddr)。当recvfrom()返回时,fromlen包含实际存入from中的数据字节数 接收一个数据报并保存源地址。 int PASCAL FAR recvfrom( SOCKET s, char FAR* buf, int len, int flags, struct sockaddr FAR from, int FAR fromlen); s:标识一个已连接套接口的描述字。 buf:接收数据缓冲区。 len:缓冲区长度。 flags:调用操作方式。 from:(可选)指针,指向装有源地址的缓冲区。 fromlen:(可选)指针,指向from缓冲区长度值。 https://blog.csdn.net/qq_26399665/article/details/52426529 //sendto/recvfrom 7.fwrite(const voidbuffer,size_t size,size_t count,FILEstream); (1)buffer:是一个指针,对fwrite来说,是要输出数据的地址。 (2)size:要写入的字节数; (3)count:要进行写入size字节的数据项的个数; (4)stream:目标文件指针。 //Server_Udp(了解) 1.FILE fopen(char path, char * mode); path为包含了路径的文件名,mode为文件打开方式 2.bind()函数把一个地址族中的特定地址赋给socket。例如对应AF_INET、AF_INET6就是把一个ipv4或ipv6地址和端口号组合赋给socket。 int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); 第二个参数是一个指向特定协议的地址结构的指针,第三个参数是该地址结构的长度。 3.size_t fread(void buffer,size_t size,size_t count,FILE stream) buffer 是读取的数据存放的内存的指针(可以是数组,也可以是新开辟的空间,buffer就是一个索引) size 是每次读取的字节数 count 是读取次数 ,k stream 是要读取的文件的指针
嵌入式&系统
# 嵌入式
刘航宇
4年前
0
1,112
5
上一页
1
...
9
10
11
...
14
下一页