- 2025-03-23
-
回复了主题帖:
【新年花灯】点亮旋转时钟数码管
补充:
本开发板基于新定义MCU(RD8G37Q48RJ)为主控,主要用于实现的旋转LED电子钟功能:LED亮灭表示秒刻度,数码管显示时间,液晶屏显示日期,BM8363时钟芯片提供RTC计时。
主控
RD8G37Q48RJ 高速 1T 8051内核 Flash MCU,48pin,8 Kbytes SRAM ,128 Kbytes Flash,0~4 Kbytes LDROM,6 Kbytes独立EEPROM,17路12位ADC,14路16位PWM,5个定时器,乘除法器,1路UART,6路USCI三选一(UART/SPI/IIC),LCD/LED驱动,CRC校验模块,模拟比较器
60个LED用于表示秒刻度
SEG(8个):(Seg8、Seg9、Seg10、Seg11、Seg12、Seg13、Seg14、Seg15)
COM(8个):(COM0、COM1、COM2、COM3、COM4、COM5、COM6、COM7)
8*8=64个LED,秒刻度使用其中60个LED.
数码管
SEG(8个):(Seg4、Seg5、Seg6、Seg7)
COM(8个):(COM0、COM1、COM2、COM3、COM4、COM5、COM6、COM7)
4*8=32个LED
新定义RD8G37的LED驱动
RD8G37系列内部集成了硬件LCD/LED显示驱动电路,可以方便用户实现LCD和LED的显示驱动。LCD和LED显示驱动二选一;4种显示驱动模式可选:8*24、6*26、5*27、4*28;
利用8(COM)*8(SEG)=64来显示电子钟60秒钟,多出的4个LED用来表示刻钟(15分钟1个刻度)。
利用8(COM)*4(SEG)=32来控制数码管。
DDIC固件库函数提供了DDIC_Control可以控制SEG和COM脚对应LCD/LED的亮灭
/*****************************************************
*函数名称:void DDIC_Control(DDIC_Control_SEG_TypeDef DDIC_Seg,uint8_t DDIC_Com,DDIC_Control_Status DDIC_Contr)
*函数功能:控制输入的SEG和COM脚对应LCD/LED的亮灭
*入口参数:
DDIC_Control_SEG_TypeDef:DDIC_Seg:选择控制的SEG口
DDIC_Control_COM_TypeDef:DDIC_Com:选择控制的COM口(uint8_t作为入参,方便进行位或操作)
DDIC_Control_Status:DDIC_Contr:控制状态
*出口参数:void
*****************************************************/
void DDIC_Control(DDIC_Control_SEG_TypeDef DDIC_Seg, uint8_t DDIC_Com,
DDIC_Control_Status DDIC_Contr)
{
if (DDIC_Contr)
{
LCDRAM[DDIC_Seg] |= DDIC_Com;
}
else
{
LCDRAM[DDIC_Seg] &= (~DDIC_Com);
}
}
先定义一个结构用于定义后面的SEG和COM对
typedef struct {
DDIC_Control_SEG_TypeDef seg;
DDIC_Control_COM_TypeDef com;
}LedSegCom;
一对SEG和COM,控制一个LED。
对于60个秒刻度,可以建立一个数组对应每个秒钟的SEG和COM:
LedSegCom secondLedSegArray[60]={
DDIC_SEG8,DDIC_COM0, //0秒
DDIC_SEG8,DDIC_COM1, //1秒
DDIC_SEG8,DDIC_COM2, //2秒
DDIC_SEG8,DDIC_COM3, //3秒
...
}
通过下面函数指定那个秒钟LED的亮灭:
void TurnOnSecondLed(unsigned char second,bit bOnOff)
{
if(bOnOff)
{
DDIC_Control(secondLedSegArray[second].seg,secondLedSegArray[second].com,DDIC_Control_ON);
}else
{
DDIC_Control(secondLedSegArray[second].seg,secondLedSegArray[second].com,DDIC_Control_OFF);
}
}
控制秒刻度亮灭
void TurnOnSecondLed(unsigned char second,bit bOnOff)
{
if(bOnOff)
{
DDIC_Control(secondLedSegArray[second].seg,secondLedSegArray[second].com,DDIC_Control_ON);
}else
{
DDIC_Control(secondLedSegArray[second].seg,secondLedSegArray[second].com,DDIC_Control_OFF);
}
}
控制刻度(15分钟)亮灭
void TurnOnQuarterHour(unsigned char quarter,bit bOnOff)
{
if(bOnOff)
{
DDIC_Control(quarterHour[quarter].seg,quarterHour[quarter].com,DDIC_Control_ON);
}else
{
DDIC_Control(quarterHour[quarter].seg,quarterHour[quarter].com,DDIC_Control_OFF);
}
}
控制数码管
数码管真值表
//0,1,2,3,...9,A,b,...,F
unsigned char digitalTruthTable[]={ //15, 16上 17右 18下, 19, 20, 21
0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x00,0x01,0x02,0x04,0x08,0x10,0x20
};
15-21:对应数码管特殊显示,如数码管上下横线亮,只有右边的竖线亮,只有左边的竖线亮等...
数码管对应的SEG和COM数组:
LedSegCom digitalTube[4][8]={
{DDIC_SEG4,DDIC_COM0,DDIC_SEG4,DDIC_COM1,DDIC_SEG4,DDIC_COM2,DDIC_SEG4,DDIC_COM3,
DDIC_SEG4,DDIC_COM4,DDIC_SEG4,DDIC_COM5,DDIC_SEG4,DDIC_COM6,DDIC_SEG4,DDIC_COM7,
},
{DDIC_SEG5,DDIC_COM0,DDIC_SEG5,DDIC_COM1,DDIC_SEG5,DDIC_COM2,DDIC_SEG5,DDIC_COM3,
DDIC_SEG5,DDIC_COM4,DDIC_SEG5,DDIC_COM5,DDIC_SEG5,DDIC_COM6,DDIC_SEG5,DDIC_COM7,
},
{DDIC_SEG6,DDIC_COM0,DDIC_SEG6,DDIC_COM1,DDIC_SEG6,DDIC_COM2,DDIC_SEG6,DDIC_COM3,
DDIC_SEG6,DDIC_COM4,DDIC_SEG6,DDIC_COM5,DDIC_SEG6,DDIC_COM6,DDIC_SEG6,DDIC_COM7,
},
{DDIC_SEG7,DDIC_COM0,DDIC_SEG7,DDIC_COM1,DDIC_SEG7,DDIC_COM2,DDIC_SEG7,DDIC_COM3,
DDIC_SEG7,DDIC_COM4,DDIC_SEG7,DDIC_COM5,DDIC_SEG7,DDIC_COM6,DDIC_SEG7,DDIC_COM7,
},
};
数码管控制函数:
void TurnOnDitialTube(unsigned char digital,unsigned char chNum)
{
unsigned char i,dtt;
dtt=digitalTruthTable[chNum];
for(i=0;i<8;i++)
{
if(dtt&0x01){
DDIC_Control(digitalTube[digital][i].seg,digitalTube[digital][i].com,DDIC_Control_ON);
}else
{
DDIC_Control(digitalTube[digital][i].seg,digitalTube[digital][i].com,DDIC_Control_OFF);
}
dtt=dtt>>1;
}
}
//控制数码管中的冒号亮灭
void TurnOnColon(bit bOnOff)
{
if(bOnOff)
{
DDIC_Control(DDIC_SEG5,DDIC_COM7,DDIC_Control_ON);
}else
{
DDIC_Control(DDIC_SEG5,DDIC_COM7,DDIC_Control_OFF);
}
}
16机制数据控制数码管
void TurnOnDitialTubeByHex(unsigned char digital,unsigned char Hex)
{
unsigned char i,dtt;
dtt=Hex;
for(i=0;i<8;i++)
{
if(dtt&0x01){
DDIC_Control(digitalTube[digital][i].seg,digitalTube[digital][i].com,DDIC_Control_ON);
}else
{
DDIC_Control(digitalTube[digital][i].seg,digitalTube[digital][i].com,DDIC_Control_OFF);
}
dtt=dtt>>1;
}
}
定义了以上函数就可以开始控制点灯了
1、依次点灯一圈,每次点亮一灯
for(i=0;i<60;i++)
{
TurnOnSecondLed(i,1);
Delay(100);
TurnOnSecondLed(i,0);
Delay(100);
}
2、奇偶分别点灯
for(j=0;j<10;j++)
{
for(i=0;i<60;i++)
{
if(i%2==0)
{
TurnOnSecondLed(i,1);
}else
TurnOnSecondLed(i,0);
Delay(100);
if(i%2==0)
{
TurnOnSecondLed(i,0);
}else
TurnOnSecondLed(i,1);
}
}
3、每隔5个灯控制依次点灯
for(j=0;j<10;j++)
{
for(i=0;i<60;i++)
{
if(i%5==0) TurnOnSecondLed(i,1);
}
Delay(1000);
for(i=0;i<60;i++)
{
if(i%5==1) TurnOnSecondLed(i,1);
}
Delay(1000);
for(i=0;i<60;i++)
{
if(i%5==2) TurnOnSecondLed(i,1);
}
Delay(1000);
for(i=0;i<60;i++)
{
if(i%5==3) TurnOnSecondLed(i,1);
}
Delay(1000);
for(i=0;i<60;i++)
{
if(i%5==4) TurnOnSecondLed(i,1);
}
Delay(1000);
for(i=0;i<60;i++)
{
TurnOnSecondLed(i,0);
}
不一一解释了,全部源码:
//************************************************************
// Copyright (c)
// FileName : main.c
// Function : Main Function
// Instructions : Contains the MCU initialization function and its H file
//************************************************************
/********************Includes************************************************************************/
#include "SC_Init.h" // MCU initialization header file, including all firmware library header files
#include "SC_it.h"
#include "..\Drivers\SCDriver_list.h"
#include "HeadFiles\SysFunVarDefine.h"
#include "ILI9225.h"
#include "ClockLed.h"
/**************************************Generated by EasyCodeCube*************************************/
//Forbid editing areas between the labels !!!
/*************************************.Generated by EasyCodeCube.************************************/
/*****************************************************************************************************
* Function Name: main
* Description : This function implements main function.
* Arguments : None
* Return Value : None
******************************************************************************************************/
//extern int yanhua();
void prewhile(void)
{
uint8_t i,j,secondIndex=0;
InitLCD();
clrScr(VGA_RED);
//GUI_WriteASCII(0,20,"Lighting",VGA_WHITE,VGA_RED);
GUI_Write16CnChar(32,43,"新年花灯",VGA_WHITE,VGA_RED);
GUI_WriteASCII8x16(12,68,"EEWORLD 2025",VGA_WHITE,VGA_RED);
for(i=0;i<60;i++)
{
TurnOnSecondLed(i,1);
Delay(100);
TurnOnSecondLed(i,0);
Delay(100);
}
clrScr(VGA_Orange_Red);
GUI_Write16CnChar(32,43,"新年花灯",VGA_WHITE,VGA_Orange_Red);
GUI_WriteASCII8x16(12,68,"EEWORLD 2025",VGA_WHITE,VGA_Orange_Red);
for(j=0;j<10;j++)
{
for(i=0;i<60;i++)
{
if(i%2==0)
{
TurnOnSecondLed(i,1);
}else
TurnOnSecondLed(i,0);
Delay(100);
if(i%2==0)
{
TurnOnSecondLed(i,0);
}else
TurnOnSecondLed(i,1);
}
}
clrScr(VGA_GREEN);
GUI_Write16CnChar(32,43,"新年花灯",VGA_WHITE,VGA_GREEN);
GUI_WriteASCII8x16(12,68,"EEWORLD 2025",VGA_WHITE,VGA_GREEN);
for(i=0;i<60;i++)
{
TurnOnSecondLed(i,0);
}
for(j=0;j<10;j++)
{
for(i=0;i<60;i++)
{
if(i%5==0) TurnOnSecondLed(i,1);
}
Delay(1000);
for(i=0;i<60;i++)
{
if(i%5==1) TurnOnSecondLed(i,1);
}
Delay(1000);
for(i=0;i<60;i++)
{
if(i%5==2) TurnOnSecondLed(i,1);
}
Delay(1000);
for(i=0;i<60;i++)
{
if(i%5==3) TurnOnSecondLed(i,1);
}
Delay(1000);
for(i=0;i<60;i++)
{
if(i%5==4) TurnOnSecondLed(i,1);
}
Delay(1000);
for(i=0;i<60;i++)
{
TurnOnSecondLed(i,0);
}
for(i=0;i<60;i++)
{
if(i%5==4) TurnOnSecondLed(i,1);
}
Delay(1000);
for(i=0;i<60;i++)
{
if(i%5==3) TurnOnSecondLed(i,1);
}
Delay(1000);
for(i=0;i<60;i++)
{
if(i%5==2) TurnOnSecondLed(i,1);
}
Delay(1000);
for(i=0;i<60;i++)
{
if(i%5==1) TurnOnSecondLed(i,1);
}
Delay(1000);
for(i=0;i<60;i++)
{
if(i%5==0) TurnOnSecondLed(i,1);
}
Delay(1000);
for(i=0;i<60;i++)
{
TurnOnSecondLed(i,0);
}
}
clrScr(VGA_BLUE);
GUI_Write16CnChar(32,43,"新年花灯",VGA_WHITE,VGA_BLUE);
GUI_WriteASCII8x16(12,68,"EEWORLD 2025",VGA_WHITE,VGA_BLUE);
for(j=0;j<20;j++)
{
for(i=0;i<60;i++)
{
TurnOnSecondLed(i,0);
}
Delay(1000);
for(i=0;i<60;i++)
{
TurnOnSecondLed(i,1);
}
Delay(1000);
}
for(i=0;i<60;i++)
{
TurnOnSecondLed(i,0);
}
clrScr(VGA_PURPLE);
GUI_Write16CnChar(32,43,"新年花灯",VGA_WHITE,VGA_PURPLE);
GUI_WriteASCII8x16(12,68,"EEWORLD 2025",VGA_WHITE,VGA_PURPLE);
for(i=0;i<4;i++)
{
TurnOnQuarterHour(i,1);
}
for(j=0;j<180;j++)
{
if(j%10==0)
{
TurnOnDitialTubeByHex(0,digitalTruthTable[16]|digitalTruthTable[20]);
TurnOnDitialTubeByHex(1,digitalTruthTable[19]);
TurnOnDitialTubeByHex(2,digitalTruthTable[16]);
TurnOnDitialTubeByHex(3,digitalTruthTable[17]|digitalTruthTable[19]);
}
else if(j%10==5)
{
TurnOnDitialTubeByHex(0,digitalTruthTable[19]|digitalTruthTable[21]);
TurnOnDitialTubeByHex(1,digitalTruthTable[16]);
TurnOnDitialTubeByHex(2,digitalTruthTable[19]);
TurnOnDitialTubeByHex(3,digitalTruthTable[16]|digitalTruthTable[18]);
}
for(i=0;i<60;i++)
{
if(i%5==0) TurnOnSecondLed(i,1);
else TurnOnSecondLed(i,0);
}
for(i=0;i<4;i++)
{
TurnOnQuarterHour(i,0);
}
TurnOnQuarterHour(j%4,1);
TurnOnSecondLed(j%60,1);
Delay(500);
}
clrScr(VGA_MAROON);
GUI_Write16CnChar(32,43,"新年花灯",VGA_WHITE,VGA_MAROON);
GUI_WriteASCII8x16(12,68,"EEWORLD 2025",VGA_WHITE,VGA_MAROON);
//点亮一个,熄灭一个
for(i=0;i<5;i++)
{
TurnOnDitialTube(0,2);
Delay(1000);
TurnOnDitialTube(0,15);
Delay(1000);
TurnOnDitialTube(1,0);
Delay(1000);
TurnOnDitialTube(1,15);
Delay(1000);
TurnOnDitialTube(2,2);
Delay(1000);
TurnOnDitialTube(2,15);
Delay(1000);
TurnOnDitialTube(3,5);
Delay(1000);
TurnOnDitialTube(3,15);
Delay(1000);
}
clrScr(VGA_OLIVE);
GUI_Write16CnChar(32,43,"新年花灯",VGA_WHITE,VGA_OLIVE);
GUI_WriteASCII8x16(12,68,"EEWORLD 2025",VGA_WHITE,VGA_OLIVE);
//按顺序点亮数码管,然后按顺序熄灭数码管
for(i=0;i<5;i++)
{
TurnOnDitialTube(0,2);
Delay(2000);
TurnOnDitialTube(1,0);
Delay(2000);
TurnOnDitialTube(2,2);
Delay(2000);
TurnOnDitialTube(3,5);
Delay(2000);
TurnOnDitialTube(0,15);
Delay(2000);
TurnOnDitialTube(1,15);
Delay(2000);
TurnOnDitialTube(2,15);
Delay(2000);
TurnOnDitialTube(3,15);
Delay(2000);
}
clrScr(VGA_RED);
GUI_Write16CnChar(32,43,"新年花灯",VGA_WHITE,VGA_RED);
GUI_WriteASCII8x16(12,68,"EEWORLD 2025",VGA_WHITE,VGA_RED);
TurnOnDitialTube(0,2);
TurnOnDitialTube(1,0);
TurnOnDitialTube(2,2);
TurnOnDitialTube(3,5);
}
void dowork(void)
{
prewhile();
}
void main(void)
{
/*<Generated by EasyCodeCube begin>*/
/*<UserCodeStart>*//*<SinOne-Tag><36>*/
IcResourceInit();
/*<UserCodeEnd>*//*<SinOne-Tag><36>*/
/*<UserCodeStart>*//*<SinOne-Tag><4>*/
/*****MainLoop*****/
prewhile();
while(1)
{
/*<UserCodeStart>*//*<SinOne-Tag><14>*/
/***User program***/
dowork();
/*<UserCodeEnd>*//*<SinOne-Tag><14>*/
/*<Begin-Inserted by EasyCodeCube for Condition>*/
}
/*<UserCodeEnd>*//*<SinOne-Tag><4>*/
/*<Generated by EasyCodeCube end>*/
}
- 2025-02-11
-
回复了主题帖:
【新年花灯】AI给的烟花效果
okhxyyo 发表于 2025-2-11 14:22
为什么说是AI给的烟花特效啊
算法是deepseek生成的
-
发表了主题帖:
【新年花灯】AI给的烟花效果
本帖最后由 sujingliang 于 2025-2-11 14:35 编辑
[localvideo]9af6415c4ee1cc63a9c39bcbb83e9b90[/localvideo]
[localvideo]24e48459ee53ae9109bb099a8225393a[/localvideo]
// 屏幕大小
#define SCREEN_WIDTH 44
#define SCREEN_HEIGHT 7
// 烟花的大小
#define FIREWORK_WIDTH 5
#define FIREWORK_HEIGHT 1
// 烟花初始位置
uint8_t firework_x=SCREEN_WIDTH-FIREWORK_WIDTH - 1; // 烟花的水平位置
uint8_t firework_y=3; // 烟花的垂直位置(从底端开始)
// 烟花移动的目标位置
#define TARGET_X (SCREEN_WIDTH - 1 - 37) // 向上移动 33 个格子
// 烟花散开后的点
#define SPARK_COUNT 15 // 散开的点数
uint8_t spark_x[SPARK_COUNT];
uint8_t spark_y[SPARK_COUNT];
uint8_t spark_dx[SPARK_COUNT]; // 散开点的水平速度
uint8_t spark_dy[SPARK_COUNT]; // 散开点的垂直速度
uint8_t matrix3[48]={0x00};
// 虚拟屏幕
uint8_t virtual_screen[SCREEN_WIDTH][SCREEN_HEIGHT]={0};
void init_firework(void) {
// 随机选择烟花的水平位置
firework_x=SCREEN_WIDTH-FIREWORK_WIDTH - 1; // 烟花的水平位置
firework_y=3; // 烟花的垂直位置(从底端开始)
// 初始化散开的点
for (uint8_t i = 0; i < SPARK_COUNT; i++) {
spark_x[i] = 5+i%5;
spark_y[i] = 2+i/3;
spark_dx[i] = (rand() % 3) - 1; // 水平速度:-1, 0, 1
spark_dy[i] = (rand() % 3) - 1; // 垂直速度:-1, 0, 1
}
}
void update_firework(void) {
if (firework_x > TARGET_X) {
// 烟花向上移动
firework_x--;
} else {
// 烟花散开
for (uint8_t i = 0; i < SPARK_COUNT; i++) {
spark_x[i] += spark_dx[i];
spark_y[i] += spark_dy[i];
}
}
}
void vs_clear_screen() {
for (uint8_t y = 0; y < SCREEN_HEIGHT; y++) {
for (uint8_t x = 0; x < SCREEN_WIDTH; x++) {
virtual_screen[x][y] = 0;
}
}
}
void draw_firework() {
if (firework_x > TARGET_X) {
// 绘制烟花的 5x3 长方形
for (uint8_t dy = 0; dy < FIREWORK_HEIGHT; dy++) {
for (uint8_t dx = 0; dx < FIREWORK_WIDTH; dx++) {
if (firework_y + dy < SCREEN_HEIGHT && firework_x + dx < SCREEN_WIDTH) {
virtual_screen[firework_x + dx][firework_y + dy] = 1;
}
}
}
} else {
// 绘制散开的点
for (uint8_t i = 0; i < SPARK_COUNT; i++) {
if (spark_x[i] < SCREEN_WIDTH && spark_y[i] < SCREEN_HEIGHT) {
virtual_screen[spark_x[i]][spark_y[i]] = 1;
}
}
}
}
vs_clear_screen(); // 清屏
// 烟花动画
init_firework();
while (1) {
// 初始化烟花
vs_clear_screen(); // 清屏
update_firework(); // 更新烟花状态
draw_firework(); // 绘制烟花
clear_screen();
vs_render_screen(); // 渲染到实际屏幕
Matrix8x24(matrix3);
Delay_Ms(10);
iTime++;
if (iTime>=50) {
break; // 烟花消失,重新初始化
}
}
- 2025-01-30
-
发表了主题帖:
【新年花灯】点亮旋转时钟数码管
本帖最后由 sujingliang 于 2025-1-31 10:18 编辑
点亮旋转时钟数码管
补充内容 (2025-3-23 09:38):
补充部分内容:详见7楼https://bbs.eeworld.com.cn/forum ... 1305480&pid=3402092
- 2025-01-26
-
回复了主题帖:
EEWORLD陪你过大年,新年积分兑换盲盒收到啦-UFUN
- 2025-01-25
-
回复了主题帖:
EEWORLD陪你过大年,新年积分兑换盲盒收到啦-UFUN
资料从这里下:
http://www.wangchaochao.top/2019/03/09/uFun-1/
有原理图
这个板子都有飞线。可能和《ufun时钟问题更改》有关。
- 2025-01-24
-
回复了主题帖:
EEWORLD陪你过大年,新年积分兑换专场来啦~好物多多还有幸运盲盒!
收到了uFun开发板,从这里找到资料:http://www.wangchaochao.top/2019/03/09/uFun-1/
小巧的板子,主控STM32F103永不过时呀,还集成了很多外设,虽然已过了多年,但仍然可以看得出当年设计者的独具匠心。
感谢EEWORLD,感谢开发板提供者。
要多多攒积分,争取每年都可以获得幸运盲盒,呵呵。
- 2025-01-22
-
回复了主题帖:
EEWORLD陪你过大年,新年积分兑换专场来啦~好物多多还有幸运盲盒!
活动很好,才看到,积分很少,已花了100积分兑换
- 2024-11-18
-
加入了学习《FollowMe 第二季:3 - EK_RA6M5 开发板入门》,观看 EK-RA6M5 开发板入门
- 2024-11-05
-
回复了主题帖:
【NUCLEO-WB09KE评测】5、微信小程序BLE调节LD3亮度
lugl4313820 发表于 2024-11-2 21:57
大佬,可以分享一下您的小程源码吗?
建议参考微信官方的资料,很详细:
https://developers.weixin.qq.com/miniprogram/dev/framework/device/ble.html
有些UP主在bilibili上也有视频说明。
https://esp-document.icce.top/%E5%B0%8F%E7%A8%8B%E5%BA%8F%E5%BC%80%E5%8F%91/18%E3%80%81%E5%B0%8F%E7%A8%8B%E5%BA%8F%E5%A2%9E%E5%8A%A0%E8%93%9D%E7%89%99%E9%80%9A%E4%BF%A1%E5%8A%9F%E8%83%BD.html
- 2024-10-08
-
回复了主题帖:
【NUCLEO-WB09KE测评】四、修改广播名 与 新增自定义服务
赞
学习了:
如果定义多个特征值报0x87错,虽然头文件定义是内寸不足
#define BLE_STATUS_OUT_OF_MEMORY ((tBleStatus)(0x87))
但是调整CFG_BLE_NUM_GATT_ATTRIBUTES可以解决
CFG_BLE_NUM_GATT_ATTRIBUTES
CFG_BLE_NUM_GATT_ATTRIBUTES must be ≥ 2.
Parameter Description:
Maximum number of Attributes that can be stored in the GATT database
When a GATT characteristic is added to the database a minimum of 2 attribute records are needed: one for the characteristic declaration and one for the characteristic value. On top of this, additional records may be needed based on the characteristic properties, in particular:
- If the characteristic has the notify or indicate property set, then one additional attribute record is needed.
- If the characteristic has the broadcast property set, then one additional attribute record is needed.
- If the characteristic has the extended property set, then one additional attribute record is needed.
In summary, one characteristic may need from 2 to 5 attribute records depending on the characteristic properties.
-
回复了主题帖:
【ST NUCLEO-WB09KE测评】-7-基于p2p_server例程实现读取特征值
赞。
学习了:
如果想触发ACI_GATT_SRV_READ_VSEVT_CODE,需要将Characteristic type设为Non-buffered。
- 2024-10-06
-
回复了主题帖:
【NUCLEO-WB09KE测评】二、卡的死死的BLE初始化
本帖最后由 sujingliang 于 2024-10-6 14:34 编辑
1、printf需要重定向
2、app_ble.c中540行左右可能需要自己加一下(好像已经加了):
/* USER CODE BEGIN APP_BLE_Init_4 */
APP_BLE_Procedure_Gap_Peripheral(PROC_GAP_PERIPH_ADVERTISE_START_FAST);
/* USER CODE END APP_BLE_Init_4 */
- 2024-09-27
-
发表了主题帖:
【NUCLEO-WB09KE评测】5、微信小程序BLE调节LD3亮度
目标
开发微信小程序建立蓝牙主机访问WB09KE蓝牙从机,发送调节参数PWM调整LD3(PB2)亮度
一、WB09KE端
1、关于PWM调节LED亮度,请参见:https://bbs.eeworld.com.cn/thread-1294722-1-1.html
2、
只建了一个GATT服务和特征值,并且特征值是可以写入,1个BYTE
3、BLE调节LD3亮度
接收到LED_SERVICE_LED_TOGGLE_WRITE_EVT后,通过*p_Notification->DataTransfered.p_Payload获得写入特征值,并将此值给PWM调节占空比。
case LED_SERVICE_LED_TOGGLE_WRITE_EVT:
/* USER CODE BEGIN Service1Char1_WRITE_EVT */
TIM_SetTIM2Compare3(*p_Notification->DataTransfered.p_Payload);
APP_DBG_MSG("LED_SERVICE_LED_TOGGLE_WRITE_EVT\r\n");
/* USER CODE END Service1Char1_WRITE_EVT */
break;
//设置 TIM 通道 3 的占空比
//compare:比较值
void TIM_SetTIM2Compare3(uint32_t compare)
{
//TIM2->CCR3=compare;
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_3, compare); // compare为新的占空比值
}
二、微信小程序端
1、将涉及BLE的功能建立了一个自定义组件
index.js
主要的思路是1、扫描蓝牙;2、连接自建蓝牙从机,连接成功后所有连接参数将可以直接用到下一步;3、通过writeBLECharacteristicValue1()发送0-255的数字。
// components/bluetooth-comp/index.js
function inArray(arr, key, val) {
for (let i = 0; i < arr.length; i++) {
if (arr[i][key] === val) {
return i;
}
}
return -1;
}
// 将字符串转为 ArrayBuffer
function str2ab(str) {
let buf = new ArrayBuffer(str.length);
let bufView = new Uint8Array(buf);
for (var i = 0, strLen = str.length; i < strLen; i++) {
bufView[i] = str.charCodeAt(i);
}
return buf;
}
function intToArrayBuffer(int) {
// 将整数转换为十六进制字符串
let hexStr = int.toString(16);
// 计算需要的字节数,如果十六进制字符串长度为奇数,需要补0以确保字节对齐
let byteLength = (hexStr.length + (hexStr.length % 2 === 0 ? 0 : 2)) / 2;
// 创建一个与计算出的字节长度相同的新的ArrayBuffer对象
let buffer = new ArrayBuffer(byteLength);
let dataView = new DataView(buffer);
// 将十六进制字符串中的每个字节转换为无符号8位整数,并写入到ArrayBuffer中
for (let i = 0; i < hexStr.length; i += 2) {
let byte = parseInt(hexStr.substr(i, 2), 16); // 将每两个字符转换为一个字节的整数
dataView.setUint8(i / 2, byte); // 将整数写入ArrayBuffer的适当位置(注意这里假设了整数是按大端序排列的)
}
return buffer; // 返回生成的ArrayBuffer对象
}
Component({
behaviors: ['wx://component-export'],
/**
* 组件的属性列表
*/
properties: {
},
/**
* 组件的初始数据
*/
// bluetooth-comp/index.js
data:{
devices: [],
connected: false,
chs: []
},
/**
* 组件的方法列表
*/
// bluetooth-comp/index.js
methods: {
/* 初始化蓝牙模块 */
openBluetoothAdapter() {
// 先关闭蓝牙模块再开启 防止断开后点连接连接不上
this.closeBluetoothAdapter();
wx.openBluetoothAdapter({
success: response => {
console.log("初始化蓝牙模块成功:openBluetoothAdapter", response);
this.startBluetoothDevicesDiscovery();
},
fail: err => {
if (err.errCode === 10001) {
/* 监听蓝牙适配器状态变化事件 */
wx.onBluetoothAdapterStateChange(res => {
console.log("监听蓝牙适配器状态变化事件:onBluetoothAdapterStateChange", res);
res.available && this.startBluetoothDevicesDiscovery();
});
}
},
});
},
/* 获取本机蓝牙适配器状态 */
getBluetoothAdapterState() {
wx.getBluetoothAdapterState({
success: res => {
console.log("getBluetoothAdapterState", res);
if (res.discovering) {
// 是否正在搜索设备
this.onBluetoothDeviceFound();
} else if (res.available) {
// 蓝牙适配器是否可用
this.startBluetoothDevicesDiscovery();
}
},
});
},
/* 开始搜寻附近的蓝牙外围设备 */
startBluetoothDevicesDiscovery() {
// 开始扫描参数
if (this._discoveryStarted) return;
this._discoveryStarted = true;
wx.startBluetoothDevicesDiscovery({
allowDuplicatesKey: true,
success: response => {
console.log("开始搜寻附近的蓝牙外围设备:startBluetoothDevicesDiscovery", response);
this.onBluetoothDeviceFound();
},
fail: err => {
console.log("搜索设备失败", err);
wx.showToast({ title: "搜索设备失败", icon: "none" });
},
});
},
/* 停止搜寻附近的蓝牙外围设备。*/
stopBluetoothDevicesDiscovery() {
console.log("停止搜寻附近的蓝牙外围设备");
wx.stopBluetoothDevicesDiscovery();
},
/* 监听搜索到新设备的事件 */
onBluetoothDeviceFound() {
wx.onBluetoothDeviceFound(res => {
res.devices.forEach(device => {
if (!device.name && !device.localName) {
return;
}
const foundDevices = this.data.devices;
const idx = inArray(foundDevices, "deviceId", device.deviceId);
const data = {};
if (idx === -1) {
data[`devices[${foundDevices.length}]`] = device;
} else {
data[`devices[${idx}]`] = device;
}
this.setData(data);
});
});
},
/* 连接蓝牙低功耗设备。*/
createBLEConnection(e) {
const ds = e.currentTarget.dataset;
const deviceId = ds.deviceId;
const name = ds.name;
wx.createBLEConnection({
deviceId,
success: () => {
this.setData({ connected: true, name, deviceId });
wx.showToast({ title: "连接蓝牙设备成功", icon: "none" });
this.getBLEDeviceServices(deviceId);
},
fail: e => {
console.log("连接失败", e.errMsg);
wx.showToast({ title: "连接失败,错误信息: " + e.errMsg, icon: "none" });
},
});
// 停止搜寻蓝牙设备
this.stopBluetoothDevicesDiscovery();
},
/* 断开与蓝牙低功耗设备的连接。 */
closeBLEConnection() {
console.log("断开与蓝牙低功耗设备的连接");
wx.showToast({ title: "已断开和蓝牙设备的连接", icon: "none" });
wx.closeBLEConnection({ deviceId: this.data.deviceId });
this.setData({ connected: false, chs: [], canWrite: false });
},
/* 获取蓝牙低功耗设备所有服务 (service) */
getBLEDeviceServices(deviceId) {
wx.getBLEDeviceServices({
deviceId,
success: res => {
for (let i = 0; i < res.services.length; i++) {
if (res.services[i].isPrimary) {
this.getBLEDeviceCharacteristics(deviceId, res.services[i].uuid);
return;
}
}
},
});
},
/* 获取蓝牙低功耗设备某个服务中所有特征 (characteristic)。 */
getBLEDeviceCharacteristics(deviceId, serviceId) {
wx.getBLEDeviceCharacteristics({
deviceId,
serviceId,
success: res => {
console.log("获取蓝牙低功耗设备某个服务中所有特征:getBLEDeviceCharacteristics");
for (let i = 0; i < res.characteristics.length; i++) {
let item = res.characteristics[i];
if (item.properties.read) {
wx.readBLECharacteristicValue({ deviceId, serviceId, characteristicId: item.uuid });
}
if (item.properties.write) {
this.setData({ canWrite: true });
this._deviceId = deviceId;
this._serviceId = serviceId;
this._characteristicId = item.uuid;
// this.writeBLECharacteristicValue();
}
if (item.properties.notify || item.properties.indicate) {
wx.notifyBLECharacteristicValueChange({
deviceId,
serviceId,
characteristicId: item.uuid,
state: true,
success(res) {
console.log("notifyBLECharacteristicValueChange success", res);
},
});
}
}
},
fail(res) {
console.error("getBLEDeviceCharacteristics", res);
},
});
// 操作之前先监听,保证第一时间获取数据
wx.onBLECharacteristicValueChange(characteristic => {
// TODO 收到的信息为ArrayBuffer类型,可根据自己的需要转换 可发送给父组件用来回显
console.log("收到原始的数据", characteristic, characteristic.value);
// 测试向设备发送数据
// this.writeBLECharacteristicValue(JSON.stringify({"FAN":"OFF"}))
});
},
/* 向蓝牙低功耗设备特征值中写入二进制数据 */
writeBLECharacteristicValue(jsonStr) {
let arrayBufferValue = str2ab(jsonStr);
console.log("发送数据给蓝牙", "原始字符串", jsonStr, "转换arrayBuffer", arrayBufferValue);
wx.writeBLECharacteristicValue({
deviceId: this._deviceId,
serviceId: this._serviceId, // 微信文档上是错误的
characteristicId: this._characteristicId,
value: arrayBufferValue, // 只能发送arrayBuffer类型数据
success(res) {
console.log("消息发送成功", res.errMsg);
wx.showToast({ title: "消息发送成功", icon: "none" });
},
fail(e) {i
console.log("发送消息失败", e);i
wx.showToast({ title: "发送消息失败,错误信息: " + e.errMsg, icon: "none" });
},
});
},
/* 向蓝牙低功耗设备特征值中写入十进制数据 */
writeBLECharacteristicValue1(i) {
let arrayBufferValue = intToArrayBuffer(i);
console.log("发送数据给蓝牙", "原始字符串", i, "转换arrayBuffer", arrayBufferValue);
wx.writeBLECharacteristicValue({
deviceId: this._deviceId,
serviceId: this._serviceId, // 微信文档上是错误的
characteristicId: this._characteristicId,
value: arrayBufferValue, // 只能发送arrayBuffer类型数据
success(res) {
console.log("消息发送成功", res.errMsg);
wx.showToast({ title: "消息发送成功", icon: "none" });
},
fail(e) {
console.log("发送消息失败", e);
wx.showToast({ title: "发送消息失败,错误信息: " + e.errMsg, icon: "none" });
},
});
},
closeBluetoothAdapter() {
console.log("关闭蓝牙模块");
wx.closeBluetoothAdapter();
this._discoveryStarted = false;
},
}
})
index.json:
{
"component": true,
"usingComponents": {}
}
index.wxml
createBLEConnection<!-- bluetooth-comp/index.wxml -->
<view style="margin: 26rpx">
<button wx:if="{{!connected}}" bindtap="openBluetoothAdapter">开始扫描</button>
<button wx:else bindtap="closeBLEConnection">断开连接 - {{name}}</button>
<view class="devices_summary">已发现 {{devices.length}} 个外围设备:</view>
<view
wx:for="{{devices}}"
wx:key="index"
data-device-id="{{item.deviceId}}"
data-name="{{item.name || item.localName}}"
bindtap="createBLEConnection"
class="device_item"
hover-class="device_item_hover">
<view style="font-size: 16px; color: #333">{{item.name}}</view>
<view style="font-size: 10px">信号强度: {{item.RSSI}}dBm</view>
<view style="font-size: 10px">UUID: {{item.deviceId}}</view>
<view style="font-size: 10px">localName: {{item.localName}}</view>
</view>
</view>
index.wxss:
/* bluetooth-comp/index.wxss */
.devices_summary {
/* margin-top: 30px; */
padding: 10px;
font-size: 16px;
}
.device_item {
border-bottom: 1px solid #eee;
padding: 10px;
color: #666;
}
.device_item_hover {
background-color: rgba(0, 0, 0, 0.1);
}
2、主程序
*.json中引入组件
{
"usingComponents": {
"bluetoothcomp":"/components/bluetooth-comp/index"
}
}
*.wxml外观
<!--pages/wifi.wxml-->
<!--
<view style="position: inherit; width: 100%; background: #d3d3d3; height: auto; left: 0rpx; top: inherit">
<icon type="success" size="40" style="position: relative; left: 31rpx; top: 6rpx"></icon>
<text style="position: relative; left: 85rpx; top: -14rpx">蓝牙</text>
<switch style="position: relative; left: 449rpx; top: -19rpx" checked="{{isBlueTooth}}" bindchange="openDialogBluetooth" />
</view>
-->
<!--bind:close="onCloseBlueTooth"-->
<view>
<bluetoothcomp id="bluetoothid"></bluetoothcomp>
</view>
<view>
<slider bindchange="slider1change" min="0" max="255" show-value="true" left-icon="cancel" right-icon="success_no_circle"/>
<text style="position: relative; left: 303rpx; top: 20rpx" >{{slidervalue}}</text>
</view>
<image style="position: relative; left: 47rpx; top: 354rpx" src="//images/wb09.jpg"/>
*.js控制部分
// pages/wifi.js
Page({
/**
* 页面的初始数据
*/
data: {
isBlueTooth:false,
bluetoothDialog:false,
slidervalue:0,
},
/**
* 生命周期函数--监听页面加载
*/
onLoad(options) {
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady() {
this.bluetoothcomp = this.selectComponent("#bluetoothid");
},
/**
* 生命周期函数--监听页面显示
*/
onShow() {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide() {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload() {
},
/**
* 页面相关事件处理函数--监听用户下拉动作
*/
onPullDownRefresh() {
},
/**
* 页面上拉触底事件的处理函数
*/
onReachBottom() {
},
/**
* 用户点击右上角分享
*/
onShareAppMessage() {
},
bluetoothChange(){
},
openDialogBluetooth(){
this.setData({bluetoothDialog:true});
},
onCloseBlueTooth(){
this.setData({bluetoothDialog:false});
},
slider1change: function(e) {
// e.detail.value 包含了当前slider的value值
this.setData({slidervalue:e.detail.value});
console.log('Slider value changed to:', this.data.slidervalue);
// 在这里你可以对获取到的value值进行进一步的处理或更新数据模型中的值
this.bluetoothcomp.writeBLECharacteristicValue1(this.data.slidervalue);
},
})
三、效果
1、小程序外观
2、运行演示
[localvideo]ca8e053f2eefc519e5e0671fe042701a[/localvideo]
- 2024-09-26
-
发表了主题帖:
【NUCLEO-WB09KE评测】4、也谈BLE从机配置及BLE点灯
本帖最后由 sujingliang 于 2024-9-26 15:23 编辑
目标
其实对于用STM32CubeMX从头配置工程,我是抗拒的,因为之前被它折腾得太惨。每次用MX开启一个新的工程,感觉就像一次新的历险。
还好NUCLEO-WB09KE的配置不用考虑mpu、xspi、EXTMEM_MANAGER等等拦路虎,感觉有得搞,并且前面大佬已经成功配置过了。
那还等什么开干。
一、配置
我尽量贴的详细些
1、RCC:一定要重视RCC
这里选择了HSE、LSE,这意味着高速晶振和低速晶振都用是外部晶振。所以HSI、LSI就不要在时钟配置中做为时钟来源,否则肯定是不起振的。
时钟图:要和RCC对应上
2、SYS配上吧
3、RADIO_TIMER
配置WIN32_BLE时有提示RADIO_TIMER需要先配置。参数默认不做修改。
4、RADIO
配置原因同上
5、UART1配置上,用来打日志
6、PKA
也是系统提示要配置
7、STM32_BLE
这个是重点但是一般还真不容易配错。
设置了1个服务,1个特征
8、DEBUG也设上,略
生成代码,我生成的是KEIL文件
二、程序
1、printf重定向要实现,略
2、main() --->while(1)好像要手工加入:
MX_APPE_Process();
3、加上BLE控制LD3(PB2)的功能
Application/User/STM32_BLE/App下,led_service_app.c
找到LED_SERVICE_LED_TOGGLE_WRITE_EVT,在后面加控制PB2和打印输出的代码
case LED_SERVICE_LED_TOGGLE_WRITE_EVT:
/* USER CODE BEGIN Service1Char1_WRITE_EVT */
HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_2);
APP_DBG_MSG("LED_SERVICE_LED_TOGGLE_WRITE_EVT\r\n");
/* USER CODE END Service1Char1_WRITE_EVT */
break;
三、效果
1、BLE调试助手操作
发现蓝牙WB09
连接WB09,可以看到3个服务:GAP、默认的GATT、自己建的GATT:Unknow Service
向Unknow Service下的唯一特征发送任何值,触发LED_SERVICE_LED_TOGGLE_WRITE_EVT消息
读缺省GATT服务特征值返回:
2、NUCLEO-WB09KE收到任意写给特征值LED_TOGGLE的操作,都会触发打印如下日志,并且PB2翻转。
其他没有描述清楚的可以直接参考STM32CubeMX的工程文件.ioc,应该可以用来生成KEIL文件:
补充内容 (2024-10-6 14:42):
app_ble.c中540行左右可能需要自己加一下:
/* USER CODE BEGIN APP_BLE_Init_4 */
APP_BLE_Procedure_Gap_Peripheral(PROC_GAP_PERIPH_ADVERTISE_START_FAST);
/* USER CODE END APP_BLE_Init_4 */
补充内容 (2024-10-6 14:42):
调试器下载需要注意:
Debug->Connect:Normal
不要选under Reset,否则STLINK无法正常工作
- 2024-09-25
-
回复了主题帖:
【NUCLEO-WB09KE测评】二、卡的死死的BLE初始化
时钟不对,应该像上面这样配
-
发表了主题帖:
【NUCLEO-WB09KE评测】3、PWM控制LD3亮度
目标
STM3WB09xE有3个通用定时器(TIM2,TIM16,TIM17)
Each general-purpose timer can be used to generate PWM outputs
本次测试,利用TIM2实现PWM输出到通道3(PB2),控制LD3亮度。
一、配置
1、时钟配置
2、TIM2
选择CHANNEL3:PWM Generation CH3
Prescaler:63
Period:499
主频:64MHZ
64000000/(64*500)=2000hz
占空比:300/500=60%
3、GPIO
PB2的修改
二、程序
1、TIM2初始化
static void MX_TIM2_Init(void)
{
/* USER CODE BEGIN TIM2_Init 0 */
/* USER CODE END TIM2_Init 0 */
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_OC_InitTypeDef sConfigOC = {0};
/* USER CODE BEGIN TIM2_Init 1 */
/* USER CODE END TIM2_Init 1 */
htim2.Instance = TIM2;
htim2.Init.Prescaler = 63;
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 499;
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
if (HAL_TIM_PWM_Init(&htim2) != HAL_OK)
{
Error_Handler();
}
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 300;
sConfigOC.OCPolarity = TIM_OCPOLARITY_LOW;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_3) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM2_Init 2 */
/* USER CODE END TIM2_Init 2 */
HAL_TIM_MspPostInit(&htim2);
}
void HAL_TIM_MspPostInit(TIM_HandleTypeDef* htim)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(htim->Instance==TIM2)
{
/* USER CODE BEGIN TIM2_MspPostInit 0 */
/* USER CODE END TIM2_MspPostInit 0 */
__HAL_RCC_GPIOB_CLK_ENABLE();
/**TIM2 GPIO Configuration
PB2 ------> TIM2_CH3
*/
GPIO_InitStruct.Pin = GPIO_PIN_2;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF3_TIM2;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* USER CODE BEGIN TIM2_MspPostInit 1 */
/* USER CODE END TIM2_MspPostInit 1 */
}
}
2、修改TIM2 CH3占空比
//设置 TIM 通道 3 的占空比
//compare:比较值
void TIM_SetTIM2Compare3(uint32_t compare)
{
//TIM2->CCR3=compare;
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_3, compare); // compare为新的占空比值
}
3、main中增加HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_3);//开启 PWM 通道 3
MX_TIM2_Init();
HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_3);//开启 PWM 通道 3
4、main while(1)中增加
调整占空比参数,改变占空比调节LD3亮度
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_Delay(10);
if(dir)led3pwmval++; //dir==1 led0pwmval 递增
else led3pwmval--; //dir==0 led0pwmval 递减
if(led3pwmval>300)dir=0; //led0pwmval 到达 300 后,方向为递减
if(led3pwmval==0)dir=1; //led0pwmval 递减到 0 后,方向改为递增
printf("led3pwmval:%d\r\n",led3pwmval);
TIM_SetTIM2Compare3(led3pwmval);
}
三、运行效果
[localvideo]59615ec0c432b61ab832a0460d4d6735[/localvideo]
- 2024-09-17
-
发表了主题帖:
【NUCLEO-WB09KE评测】2、UART中断方式串口通信
目标
为NUCLEO-WB09KE搭建基本环境,驱动LED、UART,实现UART中断方式串口通信。
跑通编译、下载流程,建立信心,为后面评测做好准备。
一、STM32CubeMX配置
MX新建一个工程,选择NUCLEO-WB09KE开发板
由于选择了开发板,涉及BSP的部分已经配置好了,缺省的引脚也做了预留。
1、BSP配置
勾选了LED,BUTTON,因为要用中断方式实现UART,所以没有勾选VCOM。
2、USART1配置
设置了中断方式
生成代码
二、代码修改
1、实现printf重定向
据说ARM官方推荐用retarget.c的方式实现printf重定向
从keil/arm/startup/拷贝一份retarget.c到Core\Src下
为了支持ARM6.xx编译,将retarget.c做如下修改
//#pragma import(__use_no_semihosting_swi)
__asm(".global __use_no_semihosting");
//extern int getkey(void); /* in Serial.c */
//struct __FILE { int handle; /* Add whatever you need here */ };
//int fgetc(FILE *f) {
// return (sendchar(getkey()));
//}
main.c中增加:
/* USER CODE BEGIN 0 */
int sendchar(int ch)
{
HAL_UART_Transmit(&huart1,(uint8_t *)&ch,1,0xffff);
return ch;
}
/* USER CODE END 0 */
2、配置USART中断接收
USART1初始化完成后,使能接收中断。
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
// 使能UART中断
if (HAL_UART_Receive_IT(&huart1, (uint8_t *)aRxBuffer, RXBUFFERSIZE) != HAL_OK)
{
Error_Handler();
}
增加中断接收处理回调函数:
HAL_UART_RxCpltCallback在aRxBuffer缓存接收满后一次。因此RXBUFFERSIZE被设置为1,这样每接收一个字符,HAL_UART_RxCpltCallback被调用一次。
当接收到1时,翻转绿灯。
为了下一次中断,需要再次设置HAL_UART_Receive_IT。
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle)
{
if (UartHandle->Instance == USART1)
{
// 处理接收到的数据
// aRxBuffer 是存储接收数据的缓冲区
if(aRxBuffer[0]==1)
{
//printf("HAL_UART_RxCpltCallback\r\n");
BSP_LED_Toggle(LED_GREEN);
aRxBuffer[0]=0;
}
// 重新使能中断以继续接收数据
if (HAL_UART_Receive_IT(&huart1, (uint8_t *)aRxBuffer, RXBUFFERSIZE) != HAL_OK)
{
Error_Handler();
}
}
}
三、运行效果
1、串口收到信息。2、通过串口向MCU发送1,绿灯翻转。
- 2024-09-16
-
回复了主题帖:
【NUCLEO-WB09KE测评】一、艰难的连接芯片 与 串口初始化
感谢呀,今天用楼主的方法解决了2个板子。
这个板子识别不到芯片的这个问题,今天我也遇到了。而且另一个H7板子也出了这个问题。真快被吓着了。怪不得这些板子都特意设计boot引脚选择,问题还是挺频发的。
- 2024-09-15
-
发表了主题帖:
【ST NUCLEO-WB09KE测评】1、开箱及随机DEMO测试
本帖最后由 sujingliang 于 2024-9-15 21:57 编辑
非常荣幸能够获得本次评测机会,我深感荣幸并衷心感谢电子工程世界平台以及意法半导体公司的鼎力支持与精心组织。
ST NUCLEO-WB09KE作为一款蓝牙低功耗无线和超低功耗的开发板,具有多个显著特点,归纳一下主要特点:
1. 强大的无线性能
符合蓝牙低功耗SIG规范v5.4:内嵌了符合蓝牙低功耗SIG规范v5.4的强大且超低功耗的无线电模块,确保连接稳定可靠,射频效率高。2.4GHz射频收发器:MCU射频板(MB2032)支持蓝牙规范v5.4,提供出色的无线连接能力。
2. 超低功耗设计
超低功耗微控制器:基于Arm® Cortex®-M0+内核的STM32WB09KE微控制器,具有出色的功耗管理能力,适用于需要长时间运行的物联网设备。
电源控制选项:提供灵活的电源选项,包括ST-LINK USB VBUS或外部源,有助于进一步降低功耗。
3. 丰富的硬件资源
存储与内存:拥有512KB闪存和64kB SRAM,满足各种应用需求。
多种接口:内置PCB天线、USB Type-C®接口、Arduino® Uno V3扩展连接器以及ST morpho接头,全面访问所有STM32 I/O,方便与其他设备或模块连接。
板载调试器:配备STLINK-V3EC调试器/编程器,支持USB重新枚举功能(大容量存储、虚拟COM端口和调试端口),便于开发和调试。
4. 强大的软件支持
STM32CubeWB0 MCU软件包:随附有全面的免费软件库和示例,支持多种集成开发环境(IDE),包括IAR Embedded Workbench®、MDK-ARM和STM32CubeIDE等。
丰富的生态系统:提供Bluetooth®低功耗和Mesh协议栈、软件、工具与资源,借助STM32Cube简化项目开发。
一、开箱拍照
1、MB2032B
MCU RF board,微控制器:STM32WB09KE
2、MB1801
Mezzanine board,主要包括:ST-LINKV3、ARDUINO® Uno接口、ST morpho headers等
二、软件包安装及资料包下载
1、安装STM32CubeMX,并install embedded software packages:STM32WB0
2、KEIL PACK安装:进入C:\Users\xxxxxx(此处用户名)\STM32Cube\Repository\STM32Cube_FW_WB0_V1.0.0\Utilities\PC_Software
解压并安装:Keil.STM32WB0x_DFP.1.0.0.zip
也可以安装STM32CubeIDE,看个人需要。
3、因为是BLE开发板,所以需要在手机上安装个BLE APP配合,ST提供了一个STBLEToolbox工具,下载地址见:https://www.st.com.cn/zh/embedded-software/stbletoolbox.html
但是安卓下载连接是下载不了的,因为懂得都懂,下载链接的地址是google开头的。
所以搜了一下,可以从这里下载:https://www.pgyer.com/camN
4、资料下载:
可以从st官网下载,也可以通过STM32CubeMX下载。这个看自己需要吧,主要下了原理图和数据手册。
C:\Users\xxxxxx(此处用户名)\STM32Cube\Repository\STM32Cube_FW_WB0_V1.0.0\Projects下也有很多DEMO可以借鉴。
三、DEMO测试
ST NUCLEO-WB09KE 随机带了一个BLE_p2pServer的demo,具体是软件包中的哪个暂时没有分辨出来。
1、上电
LD2一直闪烁,表示等待BLE client设备接入
[localvideo]fba0966aa790729349dc63d24b0d7c40[/localvideo]
2、手机上运行STBLEToolbox
可以搜到p2pS_BA,其中后两个BA和BD address最后2位一致,所以我这里的是BA,其他的板子可能是其他的2个字符。
3、connect p2pS_BA
可以看到有4个服务,其中P2P SERVER 是我们需要控制的。
4、点击最下面那个控制灯的按钮(APP通过BLE控制了板子LED)
会发现APP上的灯变黄,板子上的LD1蓝灯也亮了。
5、点击板上B1按键(通过实体按键通过BLE向APP发送消息)
APP上2902 notify,收到一个VALUE:0100。
感觉STBLEToolbox这个BLE工具不错,很形象,但是传输显示的数据好像都是HEX格式的,不可转为ASCII格式。