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…

Java并发编程实战

程序等待某个同步IO操作完成&#xff0c;CPU将处于空间状态。 线程安全---多个线程交替访问某个类&#xff0c;调用方不需做任何的同步&#xff0c;这个类始终表现出正确的行为 不共享变量变量是不可变访问变量使用同步synchronized除了实现原子性&#xff08;确定临界区&#…

spring mvc ModelAndView向前台传值

今天在做项目的时候遇到一个问题&#xff0c;把第一个页面保存的id传到第三个页面中去用&#xff0c;原来是在controller层加了一个全局变量控制的&#xff0c;可是后来发现这个变量实现不了我要的功能&#xff0c;于是查了一下&#xff0c;原来ModelAndView这个类有个构造方法…

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

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

mongo经验总结

http://wenku.baidu.com/view/7c279cbfc77da26925c5b0e4.html转载于:https://www.cnblogs.com/yuechaotian/archive/2013/02/19/2916692.html

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;打造一…

静态与非静态(转改)

这里有一个C的测试&#xff0c;由于c#的sizeof不能对一般类使用&#xff0c;所以没法试验。 class Test {int i;static int j;void Method1() { printf("Method1"); };void Method2() { printf("Method2"); };void Method3() { printf("Method3"…

【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…

冲刺省选习题集

1.火柴棒等式 单击此处看题目 考察算法&#xff1a;数学分析枚举 1 #include <iostream>2 #include <cstdio>3 using namespace std;4 5 const int match[10]{6,2,5,5,4,5,6,3,7,6};6 7 int n;8 9 int merge(int x){ 10 int sum0; 11 if(x0)return 6; 12 …

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

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

解决maven依赖冲突,这篇就够了!

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

SOAP 1.1 - 学习

SOAP 1.1 --- 每天发送SOAP request&#xff0c;不搞明白啥叫SOAP,惭愧 SOAP 1.1 XML 架构定义 <xs:schema xmlns:xs"http://www.w3.org/2001/XMLSchema" xmlns:tns"http://schemas.xmlsoap.org/soap/envelope/" targetNamespace"h…

Codeforces Round #168 (Div. 2)---A. Lights Out

Lights Outtime limit per test2 secondsmemory limit per test256 megabytesinputstandard inputoutputstandard outputLenny is playing a game on a 3  3 grid of lights. In the beginning of the game all lights are switched on. Pressing any of the lights will tog…