Here's the Gurobi code to solve the optimization problem:

```python
import gurobipy as gp

# Create a new model
m = gp.Model("protein_optimization")

# Create variables
ham_sandwiches = m.addVar(vtype=gp.GRB.INTEGER, name="ham_sandwiches")
bowls_of_cereal = m.addVar(vtype=gp.GRB.INTEGER, name="bowls_of_cereal")
black_beans = m.addVar(vtype=gp.GRB.INTEGER, name="black_beans")

# Set objective function
m.setObjective(7.18 * ham_sandwiches * bowls_of_cereal + 6.24 * bowls_of_cereal * bowls_of_cereal + 6.71 * bowls_of_cereal * black_beans, gp.GRB.MINIMIZE)

# Add constraints
m.addConstr(8 * ham_sandwiches + 10 * bowls_of_cereal >= 26, "protein_constraint1")
m.addConstr(8 * ham_sandwiches + 13 * black_beans >= 26, "protein_constraint2")
m.addConstr(10 * bowls_of_cereal + 13 * black_beans >= 34, "protein_constraint3")
m.addConstr(8 * ham_sandwiches + 10 * bowls_of_cereal + 13 * black_beans >= 34, "protein_constraint4")
m.addConstr(4 * ham_sandwiches - 3 * black_beans >= 0, "constraint5")
m.addConstr(10 * bowls_of_cereal + 13 * black_beans <= 97, "protein_constraint6")
m.addConstr(8 * ham_sandwiches + 10 * bowls_of_cereal <= 78, "protein_constraint7")


# Add upper bound on total protein (from provided resource dictionary)
m.addConstr(8 * ham_sandwiches + 10 * bowls_of_cereal + 13 * black_beans <= 117, "total_protein_limit")


# Optimize model
m.optimize()

# Print results
if m.status == gp.GRB.OPTIMAL:
    print('Obj: %g' % m.objVal)
    print('ham_sandwiches:', ham_sandwiches.x)
    print('bowls_of_cereal:', bowls_of_cereal.x)
    print('black_beans:', black_beans.x)
elif m.status == gp.GRB.INFEASIBLE:
    print('The model is infeasible.')
else:
    print('Optimization ended with status %d' % m.status)

```
