STM32 HAL 硬件IIC+DMA+简单图形库控制OLED


目录

  • 前言
  • 一、建立工程
  • 二、编写和移植
    • 前期准备
    • 驱动部分修改
  • 三、使用和验证
  • 结论


(2022年1月22日重制)本文主要是移植带简单图形库的程序,如果只是实现DMA控制,建议看【0.96寸 OLED屏实现1500Fps的帧率】STM32 软件、硬件SPI、I2C驱动总结

本文参考例程
提取码: sch3

前言

本文将介绍在STM32 HAL库下实现硬件IIC+DMA控制0.96寸 OLED屏,以及OLED图形库的移植。


在这里插入图片描述

一、建立工程

平台:野火指南者STM32F103VET6 + STM32Cube MX + Keil MDK 5

(示例)
1.选择所用MCU。
在这里插入图片描述
2.选择启用晶振在这里插入图片描述
3.选择Debug方式在这里插入图片描述
4.设置时钟树
在这里插入图片描述
5.选择合适的引脚开启I2C在这里插入图片描述
6.加入I2Cx_TX的DMA在这里插入图片描述
7.开启12Cx_event_interrupt在这里插入图片描述
8.配置完后建立工程
在这里插入图片描述

二、编写和移植

本节主要介绍移植标准库编写的oledlib图形库过程。
oledlib库原作者:MjGame
原作例程开源地址:MjGame 的例程
本文使用的oledlib库修订者:一只程序缘
本文所要移植库的开源地址:一只程序缘 的例程

git clone https://gitee.com/jiezhuonew/oledlib.git
(示例):

前期准备

1.先导入所需的文件
所用Delay文件参考《无需另配定时器在STM32 HAL下实现微秒级延时(兼容FreeRTOS)》

在这里插入图片描述
在这里插入图片描述
2.将delay.h改为我们所用的Delay.h文件
在这里插入图片描述
在这里插入图片描述
修改u16为unsigned short或uint16_t
在这里插入图片描述
在这里插入图片描述

驱动部分修改

  1. 在oled_config.h中添加#include “main.h”,并修改TRANSFER_METHOD
    在这里插入图片描述

  2. 在oled_driver.h和oled_driver.c中注释掉标准库相关的东西:在这里插入图片描述
    在这里插入图片描述
    此时编译不再弹出错误。
    在这里插入图片描述

  3. 在oled_driver.c修改I2C_WriteByte函数

	/**@brief  I2C_WriteByte,向OLED寄存器地址写一个byte的数据@param  addr:寄存器地址data:要写入的数据@retval 无*/void I2C_WriteByte(uint8_t addr, uint8_t data){
//		while (I2C_GetFlagStatus(I2CX, I2C_FLAG_BUSY));//		I2C_GenerateSTART(I2CX, ENABLE);//开启I2C1
//		while (!I2C_CheckEvent(I2CX, I2C_EVENT_MASTER_MODE_SELECT)); /*EV5,主模式*///		I2C_Send7bitAddress(I2CX, OLED_ADDRESS, I2C_Direction_Transmitter);//器件地址 -- 默认0x78
//		while (!I2C_CheckEvent(I2CX, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));//		I2C_SendData(I2CX, addr);//寄存器地址
//		while (!I2C_CheckEvent(I2CX, I2C_EVENT_MASTER_BYTE_TRANSMITTED));//		I2C_SendData(I2CX, data);//发送数据
//		while (!I2C_CheckEvent(I2CX, I2C_EVENT_MASTER_BYTE_TRANSMITTED));//		I2C_GenerateSTOP(I2CX, ENABLE);//关闭I2C1总线extern I2C_HandleTypeDef hi2c1;HAL_I2C_Mem_Write(&hi2c1, OLED_ADDRESS, addr, I2C_MEMADD_SIZE_8BIT, &data, 1, 10);}
  1. 在oled_driver.c修改OLED_CLS函数
void OLED_CLS(void)//清屏
{
//	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(0x00);
//		}
//	}extern unsigned char ScreenBuffer[SCREEN_PAGE_NUM][SCREEN_COLUMN];uint16_t i;for (i = 0; i < SCREEN_PAGE_NUM * SCREEN_COLUMN; ++i){ScreenBuffer[0][i] = 0;}OLED_FILL(ScreenBuffer[0]);
}
  1. 在oled_driver.c修改OLED_FILL函数
void OLED_FILL(unsigned char BMP[])
{
//	uint8_t i, j;unsigned char *p;p = BMP;//	for (i = 0; i < 8; i++)
//	{
//		WriteCmd(0xb0 + i); //page0-page1
//		WriteCmd(0x00);   //low column start address
//		WriteCmd(0x10);//		for (j = 0; j < 128; j++)
//		{
//			WriteDat(*p++);
//		}
//	}extern I2C_HandleTypeDef hi2c1;while(hi2c1.State != HAL_I2C_STATE_READY);HAL_I2C_Mem_Write_DMA(&hi2c1, OLED_ADDRESS, 0x40, I2C_MEMADD_SIZE_8BIT, p, SCREEN_PAGE_NUM * SCREEN_PAGEDATA_NUM);
}
  1. 注意到
//请将此函数放入1ms中断里,为图形提供时基
//系统时间基准主要用于FrameRateUpdateScreen()中固定帧率刷新屏幕
void OledTimeMsFunc(void)
{if(OledTimeMs != 0x00){ OledTimeMs--;}
}

故到stm32f1xx_it.c中声明并添加此函数
若未使用FreeRTOS则在滴答定时器中断中添加,反之在对应定时器中断中添加:

/*** @brief This function handles System tick timer.*/
void SysTick_Handler(void)
{/* USER CODE BEGIN SysTick_IRQn 0 *//* USER CODE END SysTick_IRQn 0 */HAL_IncTick();/* USER CODE BEGIN SysTick_IRQn 1 */OledTimeMsFunc();/* USER CODE END SysTick_IRQn 1 */
}
  1. 修改OLED_Init函数
void OLED_Init(void)
{WriteCmd(0xAE); //display offWriteCmd(0x20); //Set Memory Addressing Mode
//	WriteCmd(0x10); //00,Horizontal Addressing Mode;01,Vertical Addressing Mode;10,Page Addressing Mode (RESET);11,InvalidWriteCmd(0x00); //00,Horizontal Addressing Mode;01,Vertical Addressing Mode;10,Page Addressing Mode (RESET);11,InvalidWriteCmd(0xb0); //Set Page Start Address for Page Addressing Mode,0-7WriteCmd(0xc8); //Set COM Output Scan DirectionWriteCmd(0x00); //---set low column addressWriteCmd(0x10); //---set high column addressWriteCmd(0x40); //--set start line addressWriteCmd(0x81); //--set contrast control registerWriteCmd(0xff); //亮度调节 0x00~0xffWriteCmd(0xa1); //--set segment re-map 0 to 127WriteCmd(0xa6); //--set normal displayWriteCmd(0xa8); //--set multiplex ratio(1 to 64)WriteCmd(0x3F); //WriteCmd(0xa4); //0xa4,Output follows RAM content;0xa5,Output ignores RAM contentWriteCmd(0xd3); //-set display offsetWriteCmd(0x00); //-not offsetWriteCmd(0xd5); //--set display clock divide ratio/oscillator frequencyWriteCmd(0xf0); //--set divide ratioWriteCmd(0xd9); //--set pre-charge periodWriteCmd(0x22); //WriteCmd(0xda); //--set com pins hardware configurationWriteCmd(0x12);WriteCmd(0xdb); //--set vcomhWriteCmd(0x20); //0x20,0.77xVccWriteCmd(0x8d); //--set DC-DC enableWriteCmd(0x14); //WriteCmd(0xaf); //--turn on oled panelOLED_CLS();
}

其中 WriteCmd(0x20); WriteCmd(0x00); 两句函数将SSD1306的寻址方式修改为了水平寻址,能够一次性对OLED内部Graphic Display Data RAM (GDDRAM)整体更新。
见firestaradmin大佬的
《STM32 DMA-IIC刷新OLED屏(理论可达42+帧率)》
和Coder_BCM大佬的
《基于STM32F407的 中景园0.96寸OLED(IIC)的程序升级(DMA+IIC + 显存Buffer)》)
若发现行错位,则修改

	WriteCmd(0xd3); //-set display offsetWriteCmd(0x00 加或减 8的倍数); 

三、使用和验证

添加test.c,该文件源自原例程,有修改。
需要注意的是调用OLED_ShowCHinese函数的文件和oled_font.c文件的编码格式需一致:GBK。当一个为UTF-8,一个为GBK时会显示不出汉字。

/*Copyright (c) [2019] [一只程序缘 jiezhuo][https://gitee.com/jiezhuonew/oledlib] is licensed under the Mulan PSL v1.You can use this software according to the terms and conditions of the Mulan PSL v1.You may obtain a copy of Mulan PSL v1 at:http://license.coscl.org.cn/MulanPSLTHIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS ORIMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULARPURPOSE.See the Mulan PSL v1 for more details.==========此函数是oledlib图形库的综合测试函数 基本上使用到了里面的所有内容==================目前接线说明:仅仅使用到0.96寸7引脚oled 使用SPI通信方式(具体见oled_drive.c)D0  = SCK  ->	PA4		(屏幕批次不同丝印可能不同)D1  = SDA  ->	PA5RES = RES  ->	PA6DC  = DC   ->	PA7CS  = SCS  ->	PA8软件模块:oled	spi驱动beep	蜂鸣器 提示或作为led表示运行状态timer3	中断1ms 可为图形库提供时间基准uart	可作为串口连接电脑打印调试xinxidelay	系统自带的时间设置与提供延时函数视频演示信息:单片机 --- STM32F103oled   --- 采用4线SPI的7引脚0.96寸黑白双色oled图形库功能:在oledlib文件夹下作出多个c文件的分类 每个c文件的开头都有对该文件的简要说明包括打点 画线 矩形 三角形 圆 椭圆 圆角矩形 的边缘与填充还包括 字符显示 汉字显示 位图显示最后还有 oled模拟串口printf的debug字符显示:针对于字符有4种大小0-1-2-3 具体参见SetFontSize()基于大家的使用习惯0是一般大家习惯用的			此时y只能为0-7对应显示的7大行 		注意:此时x为地基大行 y为第几列2 3都是基于1的等比例放大	此时y能为0-6x对应显示的每一小行		此时为正常坐标系 x为第几小行 y为第几列中文汉字显示:中文汉字的大小为16x16		此时y也只能为0-7对应显示的7大行		注意:此时x为地基大行 y为第几列取模说明:取模软件采用PCtoLCD2002字符 汉字 和 位图的取模方式和设置都在font.c和bmp.c中有注释用户调用函数:在draw_api.h中提供了所有函数的接口 可在其中查看所有函数的简要功能移植说明:1.移植图形库仅需要准备好底层驱动 在oled_driver.c中作出修改即可 在该c文件开头有说明2.若需要对test.c中的动画效果进行测试 还需要为函数OledTimeMsFunc()提供时间基准3.库函数使用的延时函数是DelayMs() 移植后由单片机型号补充调整DelayMs()图形库本质:该图形库本质为对一数组进行操作 然后刷新整个数组到屏幕中实现效果因此相似点阵屏(oled/TFT/大小尺寸/点阵/液晶)也可以使用 根据像素可参见oled_config.h详细的注释:如果是使用为用途 了解test.c和draw_api.c即可 做出花里胡哨的UI界面在本人阅读代码和注释的过程中 发现很多结构和函数都值得学习 仔细理解理解GUI和本图形库的关系:gui是一个以图形界面来进行人机交互的系统 gui是拥有窗口、菜单、控件、对话框等交互的图形接口这个只是一个图形库 类似于c++上的easyx图形库 是没有图形接口的 只提供绘图和显示的功能图形库可以算是gui的一部分,也可以自己以图形库继续封装为gui库代码容量:除去位图 Code=26254 RO-data=3754 RW-data=100 ZI-data=4108原作的话:为了做这个绘制图形库,我参考了很多其他的算法,花了大量时间去做移植优化,其中参考最多的是github中的arduboy游戏机,大部分图形是移植它的,现在是最初的初稿版本,还有很多地方需要优化改进。我想要将这个图形库做大,后续会加入更多有趣的东西,和模块,代码都是用最简单的方式编写的,都是开源的。后续也会加上注释说明,让更多人以单片机和oled屏来入门硬件编程,如果你使用了该库,请标明出处。b站关注oximeterg,可获取该库的最新版本和消息。注意:绘制填充或实心的图形,影响刷新效率(待优化中)
*/// #include "test.h"
#include "draw_api.h"
#include "../Delay/Delay.h"
#include "stdlib.h"
#include "stdio.h"
#include "math.h"void ShowStars(void);
void ShowWatch(void);
void ShowPolygon(void);
void ShowSnow(void);void demo(void)
{int i,j;//demo演示ClearScreen();DrawBitmap(0,0,Panda,128,64);UpdateScreen();DelayMs(1000);//字符ClearScreen();SetFontSize(1);DrawString(0,0,"test");UpdateScreen();DelayMs(1000);SetFontSize(2);DrawString(0,8,"test");UpdateScreen();DelayMs(1000);SetFontSize(3);DrawString(0,24,"test");UpdateScreen();DelayMs(1000);//汉字测试ClearScreen();OLED_ShowCHinese(0,0,"一只程序缘");UpdateScreen();DelayMs(1000);OLED_ShowCHinese(2,0,"一只程序缘一只程序缘一只程序缘一只程序缘");UpdateScreen();DelayMs(1000);//数字测试ClearScreen();for(i=0; i<300; i++){SetFontSize(0);DrawNum(0,96,i,4);SetFontSize(1);DrawNum(0,16,i,4);SetFontSize(2);DrawNum(0,24,i,4);SetFontSize(3);DrawNum(0,40,i,4);UpdateScreen();}//串口debugDelayMs(100);ClearScreen();for(i=0; i<256; i++){OledPrintf("num:%d cha:%c hex:%x\r\n",i,i,i);}DelayMs(100);//划线ClearScreen();for(i=0; i<20; i++){DrawLine(0,0,i*10,63);UpdateScreen();}for(i=0; i<20; i++){DrawLine(128,0,128-i*10,63);UpdateScreen();}DelayMs(100);//矩形for(j=0; j<2; j++){if(j==0)ClearScreen();for(i=0; i<31; i+=2){DrawRect2(i*2,i,128-i*4,64-2*i);//画矩形外框UpdateScreen();}if(j==0)ClearScreen();DelayMs(100);for(i=31; i>0; i-=2){DrawFillRect2(i*2,i,128-i*4,64-2*i);//画实心矩形UpdateScreen();}SetDrawColor(pix_black);//划线颜色SetFillcolor(pix_black);//填充颜色}SetDrawColor(pix_white);SetFillcolor(pix_white);//圆角矩形for(j=0; j<2; j++){if(j==0)ClearScreen();for(i=0; i<25; i+=2){DrawRoundRect(i*2,i,128-i*4,64-2*i,8);UpdateScreen();}if(j==0)ClearScreen();DelayMs(100);for(i=25; i>2; i-=2){DrawfillRoundRect(i*2,i,128-i*4,64-2*i,8);UpdateScreen();}SetDrawColor(pix_black);SetFillcolor(pix_black);}SetDrawColor(pix_white);SetFillcolor(pix_white);DelayMs(100);//椭圆ClearScreen();DrawEllipse(63,31,63,31);UpdateScreen();DelayMs(500);ClearScreen();DrawEllipse(63,31,16,31);UpdateScreen();DelayMs(500);ClearScreen();DrawFillEllipse(63,31,63,31);UpdateScreen();DelayMs(500);ClearScreen();DrawFillEllipse(63,31,16,31);UpdateScreen();DelayMs(500);//圆ClearScreen();DrawCircle(63,31,30);UpdateScreen();DelayMs(500);ClearScreen();DrawFillCircle(63,31,30);UpdateScreen();DelayMs(500);//三角形ClearScreen();DrawTriangle(5,10,100,30,60,50);UpdateScreen();DelayMs(500);ClearScreen();DrawFillTriangle(5,10,100,30,60,50);UpdateScreen();DelayMs(500);//绘制图形图片 位图ClearScreen();DrawBitmap(0,0,BmpTest1,16,16);UpdateScreen();DelayMs(500);DrawBitmap(16,0,BmpTest2,32,32);UpdateScreen();DelayMs(500);DrawBitmap(48,0,BmpTest3,64,64);UpdateScreen();DelayMs(500);//圆弧ClearScreen();for(i=0; i<360; i++){DrawArc(63,31,30,0,i);	//画圆弧UpdateScreen();DelayMs(25);ClearScreen();}DrawCircle(63,31,30);		//画圆UpdateScreen();DelayMs(100);for(i=0; i<10; i++){DrawFillCircle(63,31,i);	//在中心填充圆DrawCircle(63,31,30);UpdateScreen();DelayMs(25);ClearScreen();}//绕点for(i=0; i<720; i++) //转720度2圈{TypeXY temp;SetAngle(i);					//设置角度SetRotateCenter(63,31);			//设置圆心temp=GetRotateXY(63,31+30);		//讲已知坐标旋转角度DrawFillCircle(temp.x,temp.y,5);//画出算出的位置DrawCircle(63,31,30);			//画出轨迹DrawFillCircle(63,31,10);		//填充中心UpdateScreen();					//更新屏幕ClearScreen();}//向右边平移for(i=0; i<95; i++){TypeXY temp;					//其实就是上面继续旋转SetAngle(720+i);				//画图的时候x+偏移量SetRotateCenter(63+i,31);temp=GetRotateXY(63+i,31+30);DrawFillCircle(temp.x,temp.y,5);DrawCircle(63+i,31,30);DrawFillCircle(63+i,31,10);UpdateScreen();ClearScreen();}//动画ShowStars();	//星空动画ShowWatch();	//时钟动画ShowPolygon();	//多边形动画
//	ShowSnow();		//下雪动画DelayMs(100);//结束ClearScreen();SetFontSize(2);DrawString(8,16," Show End ");	//显示字符串UpdateScreen();DelayMs(1000);ClearScreen();DrawBitmap(0,10,Like,128,40);	//三连图片UpdateScreen();DelayMs(1000);
}/
//星空动画
void ShowStars(void)
{int i;int count=0;int fps=60;typedef struct START{short x;short y;short speed;unsigned char speedcount;unsigned char isexist;} Star;Star star[128]= {0};srand(2);for(i=0; i<128; i++){if(star[i].isexist==0){//设置128个()星星的初始信息star[i].x=rand()%127;		//随机生成初始x坐标star[i].y=rand()%64;		//随机生成y的坐标star[i].speedcount=0;star[i].speed=rand()%8+1;	//1-8的数star[i].isexist=1;}}while(1){if(FrameRateUpdateScreen(fps)==1)	//在此函数中定时刷新屏{count++;if(count>=fps*10)   			//10秒钟时间到达之后跳出循环结束动画return;}//此段函数一直在运行//依次画出128个星星for(i=0; i<128; i++){//如果这一个星星已经移动到退出屏幕界面//则在最左侧重新生成一颗新星星if(star[i].isexist==0){star[i].x=0;star[i].y=rand()%64;star[i].speed=rand()%6+1;star[i].speedcount=0;star[i].isexist=1;}else{star[i].speedcount++;if(star[i].x>=124)			//标记已经退出屏幕star[i].isexist=0;//清除上一个时刻画的星星(的尾巴) 不管有没有操作 都进行清除操作SetDrawColor(pix_black);DrawLine(star[i].x,star[i].y,star[i].x,star[i].y);SetDrawColor(pix_white);if(star[i].speedcount==star[i].speed)	//运行时间到了一定的长度{star[i].speedcount=0;				//复位运行时间并向右移一格star[i].x+=1;						//总之星星的结束需要在这经历124次}										//只不过有的更快 就能移动更快//从头到尾画出整条星星 不管星星是否已经变化DrawLine(star[i].x, star[i].y, star[i].x+(6/star[i].speed)-1, star[i].y);}}}
}
//时钟动画
//钟 小时 分钟 秒,
void RoundClock(int hours,int minute,int sec)
{unsigned char i=0;TypeXY hourspoint,minutepoint,secpoint,tmp1,tmp2;//时针SetRotateValue(63,31,hours*30+(minute*30)/60,1);hourspoint=GetRotateXY(63-14,31);DrawLine(63,31,hourspoint.x,hourspoint.y);//分针SetRotateValue(63,31,minute*6+(sec*6)/60,1);minutepoint=GetRotateXY(63-21,31);DrawLine(63,31,minutepoint.x,minutepoint.y);//秒针SetRotateValue(63,31,sec*6,1);secpoint=GetRotateXY(63-28,31);DrawLine(63,31,secpoint.x,secpoint.y);//表盘for(i=0; i<12; i++){SetRotateValue(63,31,i*30,1);tmp1=GetRotateXY(63-29,31);tmp2=GetRotateXY(63-24,31);DrawLine(tmp1.x,tmp1.y,tmp2.x,tmp2.y);}DrawFillCircle(63,31,2);DrawCircle(63,31,30);UpdateScreen();DelayMs(25);ClearScreen();
}void ShowWatch(void)
{int i,j,z;int count=0;for(i=0; i<12; i++)for(j=0; j<60; j++)for(z=0; z<60; z++){RoundClock(i,j,z);count++;if(count>=800)return;}
}/
//多边形动画
void ShowPolygon(void)
{int x0=63,y0=31;		//正多边形的外接圆的圆心unsigned char i =0,j;int n=1,r=31;			//画正n边形 大小半径31int v=1,count=0;		//每个相邻的多边形隔1 画count次后退出int x[30],y[30];while(1){ClearScreen();for(i=0; i<n; i++){x[i]=r*cos(2*3.1415926*i/n)+x0;y[i]=r*sin(2*3.1415926*i/n)+y0;}for(i=0; i<=n-2; i++){for(j=i+1; j<=n-1; j++)DrawLine(x[i],y[i],x[j],y[j]);}n+=v;if(n==20||n==0)v=-v;UpdateScreen();DelayMs(25);		//延时停顿100msif(++count==90){count=0;return ;}}
}//下雪的函数 和星空类似 
void ShowSnow(void)
{int a[66],i,num=0;int count=0;int fps=60;struct Snow{short x;short y;short speed;} snow[100];srand(1);for(i=0; i<66; i++)a[i]=(i-2)*10;ClearScreen();while(1){if(FrameRateUpdateScreen(fps)==1)	//在此函数中定时刷新屏{count++;if(count>=fps*10)   			//10秒钟时间到达之后跳出循环结束动画return;}if(num!=100){snow[num].speed=1+rand()%4;i=rand()%66;snow[num].x=a[i];snow[num].y=0;num++;}for(i=0; i<num; i++){snow[i].y+=snow[i].speed;DrawPixel(snow[i].x,snow[i].y+1);DrawPixel(snow[i].x+1,snow[i].y);DrawPixel(snow[i].x,snow[i].y);DrawPixel(snow[i].x-1,snow[i].y);DrawPixel(snow[i].x,snow[i].y-1);if(snow[i].y>63){snow[i].y=0;}}UpdateScreen();DelayMs(25);ClearScreen();}
}

在main.c文件中包含必要的头文件

//...
#include "main.h"/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "../Delay/Delay.h"
#include "../oledlib/draw_api.h"
/* USER CODE END Includes */
//...

添加初始化函数并测试demo

//.../* USER CODE BEGIN 2 */delay_init();InitGraph();/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */void demo(void);demo();}/* USER CODE END 3 */
//...

效果如下
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


结论

相比于普通的硬件IIC控制屏幕,改用DMA驱动后,刷新率得到了很大提升。其速度提升的原理为《STM32 DMA-IIC刷新OLED屏(理论可达42+帧率)》

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/400877.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python创建分类器小结

&#x1f680; 优质资源分享 &#x1f680; 学习路线指引&#xff08;点击解锁&#xff09;知识定位人群定位&#x1f9e1; Python实战微信订餐小程序 &#x1f9e1;进阶级本课程是python flask微信小程序的完美结合&#xff0c;从项目搭建到腾讯云部署上线&#xff0c;打造一…

SPOJ 1676 矩阵乘法+DP

题意&#xff1a; 给定N (1 ≤ N ≤ 10)个长度不超过6的单词,求由大写字母组成长度为L的包含至少一个给定单词的字符串有多少种,答案 mod 10007,(1 ≤ L ≤ 10^6)。 题解&#xff1a; 这个题最早是在一个关于trie图的论文中看到了&#xff0c;最近jzh又讲到了这个题&#xff0c…

go-zero微服务实战系列(三、API定义和表结构设计)

&#x1f680; 优质资源分享 &#x1f680; 学习路线指引&#xff08;点击解锁&#xff09;知识定位人群定位&#x1f9e1; Python实战微信订餐小程序 &#x1f9e1;进阶级本课程是python flask微信小程序的完美结合&#xff0c;从项目搭建到腾讯云部署上线&#xff0c;打造一…

STM32 串口DMA接收 Openmv / K210 整数、小数字符串数据 (基于HAL库)

目录前言一、工程配置二、串口DMA部分代码1.源文件UART_DMA.c2.头文件UART_DMA.h3.stm32f1xx_it.c的修改4.串口收发DMA测试三、字符串数字提取代码1.源文件NumAndStr.c:2.头文件NumAndStr.h:3.测试:四、Openmv / K210 发送、STM32接收测试总结修订版本UART_DMA.cUART_DMA.h平台…

6000字|22张图 带你彻底弄懂Zookeeper分布式锁

&#x1f680; 优质资源分享 &#x1f680; 学习路线指引&#xff08;点击解锁&#xff09;知识定位人群定位&#x1f9e1; Python实战微信订餐小程序 &#x1f9e1;进阶级本课程是python flask微信小程序的完美结合&#xff0c;从项目搭建到腾讯云部署上线&#xff0c;打造一…

【HDU2896】病毒侵袭——ac自动机

网上很多代码都略显繁琐&#xff0c;看了一下yy dalao的代码感觉很好&#xff0c;但他懒得打题解&#xff08;好吧我也是 以0为根节点的话&#xff0c;我把yy的一段代码删了改用fail[c]x0?0:ch[fail[x]][i];来实现特判&#xff0c;效果还不错&#xff01;也算是AC自动机的模版…

经典 HTML5 Javascript 俄罗斯方块游戏

Blockrain.js 是一个使用 HTML5 & JavaScript 开发的经典俄罗斯方块游戏。只需要复制和粘贴一段代码就可以玩起来了。最重要的是&#xff0c;它是响应式的&#xff0c;无论你的显示屏多么宽都能自动匹配。你可以自定义你想要的颜色以适应您的网站&#xff0c;也可以调整方块…

【电赛PID半天入门】从接触编码器到调出好康的PID波形

从接触编码器到调出好康的PID波形认识电机及编码器只需动动手指&#xff0c;就能让STM32得到电机转过的角度让电机转起来认识PID控制①比例调节器②积分调节③微分调节④比例积分微分调节数字PID调节器&#xff08;1&#xff09;数字PID位置型控制算法&#xff08;2&#xff09…

算法的复杂度分析

&#x1f680; 优质资源分享 &#x1f680; 学习路线指引&#xff08;点击解锁&#xff09;知识定位人群定位&#x1f9e1; Python实战微信订餐小程序 &#x1f9e1;进阶级本课程是python flask微信小程序的完美结合&#xff0c;从项目搭建到腾讯云部署上线&#xff0c;打造一…

PHP面向对象 封装与继承

知识点&#xff1a; PHP封装三个关键词&#xff1a; 一、public 公有的&#xff0c;被public修饰的属性和方法&#xff0c;对象可以任意访问和调用 二、private 私有的&#xff0c;被private修饰的属性和方法&#xff0c;只能在类内部的方法可以进行调用&#xff0c;或者被子类…

POJ 1380 坐标旋转

题意&#xff1a; 问第二个矩形能不能放进第一个矩形中。 题解&#xff1a; 暴力旋转第二个矩形&#xff0c;判断左右、上下是否同时小于第一个矩形 当然&#xff0c;数学推导也可以&#xff0c;挺简单的相似神马的胡搞就行~ View Code 1 #include <iostream>2 #include…

MSP430F5529 DriverLib 库函数学习笔记(一)时钟配置和闪烁LED

目录一、新建工程二、时钟树时钟系统结构时钟系统的原理时钟树配置实战三、点灯工程师封装好的初始化函数平台&#xff1a;Code Composer Studio 10.3.1 MSP430F5529 LaunchPad™ Development Kit (MSP‑EXP430F5529LP) 一、新建工程 二、时钟树 时钟系统结构 &#xff08;1&…

libcurl上传文件

libcurl参数很多&#xff0c;一不小心就容易遇到问题。曾经就遇到过一个很蛋疼的问题&#xff1a;libcurl断点下载>> 这里主要汇总一下&#xff0c;libcurl上传的二种方式&#xff1a; 1、直接上传文件&#xff0c;类似form表单<input type”file” />&#xff0c;…

MSP430F5529 DriverLib 库函数学习笔记(二)GPIO

目录硬知识一、MSP430单片机端口概述二、通用IO端口输出特性三、端口P1和P21&#xff0e;输入寄存器PxIN2&#xff0e;输出寄存器PxOUT3&#xff0e;方向寄存器PxDIR4&#xff0e;上拉/下拉电阻使能寄存器PxREN5&#xff0e;输出驱动能力调节寄存器PxDS6&#xff0e;功能选择寄…

MSP430F5529 DriverLib 库函数学习笔记(三)认识中断

目录一、硬知识中断的基本概念MSP430单片机中断源中断响应过程中断返回过程中断嵌套二、msp430f5529.h中所列的中断向量宏定义平台&#xff1a;Code Composer Studio 10.3.1 MSP430F5529 LaunchPad™ Development Kit (MSP‑EXP430F5529LP) 一、硬知识 中断的基本概念 中断…

推荐系统相关算法

摘要&#xff1a; 热门推荐 协同过滤算法 矩阵分解 基于内容的推荐&#xff08;文本&#xff0c;标签&#xff0c;特征/profile&#xff09; 基于图的算法 内容&#xff1a; 热门推荐&#xff1a; 热门推荐本质上是一个排行榜&#xff0c;可能会考虑到时间衰减&#xff0c;商品…

冒泡排序的简单理解

&#x1f680; 优质资源分享 &#x1f680; 学习路线指引&#xff08;点击解锁&#xff09;知识定位人群定位&#x1f9e1; Python实战微信订餐小程序 &#x1f9e1;进阶级本课程是python flask微信小程序的完美结合&#xff0c;从项目搭建到腾讯云部署上线&#xff0c;打造一…

司机和售票员问题 信号signal注册一例

#include <stdio.h> #include <stdlib.h> #include <signal.h>pid_t pid;void driver_handler(int signo) //司机的信号处理函数 {if (signo SIGUSR1)printf("Lets go!\n");if (signo SIGUSR2)printf("Stop the bus!\n");if (signo …

MSP430F5529 DriverLib 库函数学习笔记(四)UART通信

目录硬知识USCI通信模块USCI的UART模式1. USCI初始化和复位2. 异步通信字符格式3. 异步多机通信模式4. 自动波特率检测5. IrDA编码和解码6. 自动错误检测7. USCI接收使能8. USCI发送使能9. UART波特率的产生10. UART波特率的设置&#xff08;重要&#xff09;&#xff08;1&…

MSP430F5529 DriverLib 库函数学习笔记(四点五)printf打印输出

目录代码实现使相应工程支持打印浮点数实验结果平台&#xff1a;Code Composer Studio 10.3.1 MSP430F5529 LaunchPad™ Development Kit (MSP‑EXP430F5529LP)代码实现 重定向fputc(int ch, FILE *f)直接使用printf的方法只有字符串和%s打印正常&#xff0c;数字打印不出来…